xref: /titanic_53/usr/src/uts/sun4/io/pcicfg.c (revision 269473047d747f7815af570197e4ef7322d3632c)
1*26947304SEvan Yan /*
2*26947304SEvan Yan  * CDDL HEADER START
3*26947304SEvan Yan  *
4*26947304SEvan Yan  * The contents of this file are subject to the terms of the
5*26947304SEvan Yan  * Common Development and Distribution License (the "License").
6*26947304SEvan Yan  * You may not use this file except in compliance with the License.
7*26947304SEvan Yan  *
8*26947304SEvan Yan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*26947304SEvan Yan  * or http://www.opensolaris.org/os/licensing.
10*26947304SEvan Yan  * See the License for the specific language governing permissions
11*26947304SEvan Yan  * and limitations under the License.
12*26947304SEvan Yan  *
13*26947304SEvan Yan  * When distributing Covered Code, include this CDDL HEADER in each
14*26947304SEvan Yan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*26947304SEvan Yan  * If applicable, add the following below this CDDL HEADER, with the
16*26947304SEvan Yan  * fields enclosed by brackets "[]" replaced with your own identifying
17*26947304SEvan Yan  * information: Portions Copyright [yyyy] [name of copyright owner]
18*26947304SEvan Yan  *
19*26947304SEvan Yan  * CDDL HEADER END
20*26947304SEvan Yan  */
21*26947304SEvan Yan /*
22*26947304SEvan Yan  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*26947304SEvan Yan  * Use is subject to license terms.
24*26947304SEvan Yan  */
25*26947304SEvan Yan 
26*26947304SEvan Yan /*
27*26947304SEvan Yan  *     PCI configurator (pcicfg)
28*26947304SEvan Yan  */
29*26947304SEvan Yan 
30*26947304SEvan Yan #include <sys/isa_defs.h>
31*26947304SEvan Yan 
32*26947304SEvan Yan #include <sys/conf.h>
33*26947304SEvan Yan #include <sys/kmem.h>
34*26947304SEvan Yan #include <sys/debug.h>
35*26947304SEvan Yan #include <sys/modctl.h>
36*26947304SEvan Yan #include <sys/autoconf.h>
37*26947304SEvan Yan #include <sys/hwconf.h>
38*26947304SEvan Yan #include <sys/ddi_impldefs.h>
39*26947304SEvan Yan #include <sys/fcode.h>
40*26947304SEvan Yan #include <sys/pci.h>
41*26947304SEvan Yan #include <sys/pcie.h>
42*26947304SEvan Yan #include <sys/pcie_impl.h>
43*26947304SEvan Yan #include <sys/ddi.h>
44*26947304SEvan Yan #include <sys/sunddi.h>
45*26947304SEvan Yan #include <sys/sunndi.h>
46*26947304SEvan Yan #include <sys/pci_cap.h>
47*26947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h>
48*26947304SEvan Yan #include <sys/ndi_impldefs.h>
49*26947304SEvan Yan 
50*26947304SEvan Yan #define	PCICFG_DEVICE_TYPE_PCI	1
51*26947304SEvan Yan #define	PCICFG_DEVICE_TYPE_PCIE	2
52*26947304SEvan Yan 
53*26947304SEvan Yan #define	EFCODE21554	/* changes for supporting 21554 */
54*26947304SEvan Yan 
55*26947304SEvan Yan static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t);
56*26947304SEvan Yan static int pcicfg_free_resource(dev_info_t *, pci_regspec_t, pcicfg_flags_t);
57*26947304SEvan Yan static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
58*26947304SEvan Yan 
59*26947304SEvan Yan #ifdef	PCICFG_INTERPRET_FCODE
60*26947304SEvan Yan static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *,
61*26947304SEvan Yan     uint_t, uint_t, uint_t, int32_t, pci_regspec_t *);
62*26947304SEvan Yan #endif	/* PCICFG_INTERPRET_FCODE */
63*26947304SEvan Yan 
64*26947304SEvan Yan /*
65*26947304SEvan Yan  * ************************************************************************
66*26947304SEvan Yan  * *** Implementation specific local data structures/definitions.	***
67*26947304SEvan Yan  * ************************************************************************
68*26947304SEvan Yan  */
69*26947304SEvan Yan 
70*26947304SEvan Yan static	int	pcicfg_start_devno = 0;	/* for Debug only */
71*26947304SEvan Yan 
72*26947304SEvan Yan #define	PCICFG_MAX_DEVICE 32
73*26947304SEvan Yan #define	PCICFG_MAX_FUNCTION 8
74*26947304SEvan Yan #define	PCICFG_MAX_ARI_FUNCTION 256
75*26947304SEvan Yan #define	PCICFG_MAX_REGISTER 64
76*26947304SEvan Yan #define	PCICFG_MAX_BUS_DEPTH 255
77*26947304SEvan Yan 
78*26947304SEvan Yan #define	PCICFG_NODEVICE 42
79*26947304SEvan Yan #define	PCICFG_NOMEMORY 43
80*26947304SEvan Yan #define	PCICFG_NOMULTI	44
81*26947304SEvan Yan 
82*26947304SEvan Yan #define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
83*26947304SEvan Yan #define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
84*26947304SEvan Yan #define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
85*26947304SEvan Yan 
86*26947304SEvan Yan #define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
87*26947304SEvan Yan #define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
88*26947304SEvan Yan #define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
89*26947304SEvan Yan #define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
90*26947304SEvan Yan 
91*26947304SEvan Yan #define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
92*26947304SEvan Yan #define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
93*26947304SEvan Yan 
94*26947304SEvan Yan #define	PCICFG_MEMGRAN 0x100000
95*26947304SEvan Yan #define	PCICFG_IOGRAN 0x1000
96*26947304SEvan Yan #define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
97*26947304SEvan Yan 
98*26947304SEvan Yan #define	PCICFG_MEM_MULT 4
99*26947304SEvan Yan #define	PCICFG_IO_MULT 4
100*26947304SEvan Yan #define	PCICFG_RANGE_LEN 2 /* Number of range entries */
101*26947304SEvan Yan 
102*26947304SEvan Yan static int pcicfg_slot_busnums = 8;
103*26947304SEvan Yan static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
104*26947304SEvan Yan static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */
105*26947304SEvan Yan static int pcicfg_chassis_per_tree = 1;
106*26947304SEvan Yan static int pcicfg_sec_reset_delay = 1000000;
107*26947304SEvan Yan 
108*26947304SEvan Yan /*
109*26947304SEvan Yan  * The following typedef is used to represent a
110*26947304SEvan Yan  * 1275 "bus-range" property of a PCI Bus node.
111*26947304SEvan Yan  * DAF - should be in generic include file...
112*26947304SEvan Yan  */
113*26947304SEvan Yan 
114*26947304SEvan Yan typedef struct pcicfg_bus_range {
115*26947304SEvan Yan 	uint32_t lo;
116*26947304SEvan Yan 	uint32_t hi;
117*26947304SEvan Yan } pcicfg_bus_range_t;
118*26947304SEvan Yan 
119*26947304SEvan Yan typedef struct pcicfg_range {
120*26947304SEvan Yan 
121*26947304SEvan Yan 	uint32_t child_hi;
122*26947304SEvan Yan 	uint32_t child_mid;
123*26947304SEvan Yan 	uint32_t child_lo;
124*26947304SEvan Yan 	uint32_t parent_hi;
125*26947304SEvan Yan 	uint32_t parent_mid;
126*26947304SEvan Yan 	uint32_t parent_lo;
127*26947304SEvan Yan 	uint32_t size_hi;
128*26947304SEvan Yan 	uint32_t size_lo;
129*26947304SEvan Yan 
130*26947304SEvan Yan } pcicfg_range_t;
131*26947304SEvan Yan 
132*26947304SEvan Yan typedef struct hole hole_t;
133*26947304SEvan Yan 
134*26947304SEvan Yan struct hole {
135*26947304SEvan Yan 	uint64_t	start;
136*26947304SEvan Yan 	uint64_t	len;
137*26947304SEvan Yan 	hole_t		*next;
138*26947304SEvan Yan };
139*26947304SEvan Yan 
140*26947304SEvan Yan typedef struct pcicfg_phdl pcicfg_phdl_t;
141*26947304SEvan Yan 
142*26947304SEvan Yan struct pcicfg_phdl {
143*26947304SEvan Yan 
144*26947304SEvan Yan 	dev_info_t	*dip;		/* Associated with the attach point */
145*26947304SEvan Yan 	pcicfg_phdl_t	*next;
146*26947304SEvan Yan 
147*26947304SEvan Yan 	uint64_t	memory_base;	/* Memory base for this attach point */
148*26947304SEvan Yan 	uint64_t	memory_last;
149*26947304SEvan Yan 	uint64_t	memory_len;
150*26947304SEvan Yan 	uint32_t	io_base;	/* I/O base for this attach point */
151*26947304SEvan Yan 	uint32_t	io_last;
152*26947304SEvan Yan 	uint32_t	io_len;
153*26947304SEvan Yan 
154*26947304SEvan Yan 	int		error;
155*26947304SEvan Yan 	uint_t		highest_bus;	/* Highest bus seen on the probe */
156*26947304SEvan Yan 
157*26947304SEvan Yan 	hole_t		mem_hole;	/* Memory hole linked list. */
158*26947304SEvan Yan 	hole_t		io_hole;	/* IO hole linked list */
159*26947304SEvan Yan 
160*26947304SEvan Yan 	ndi_ra_request_t mem_req;	/* allocator request for memory */
161*26947304SEvan Yan 	ndi_ra_request_t io_req;	/* allocator request for I/O */
162*26947304SEvan Yan };
163*26947304SEvan Yan 
164*26947304SEvan Yan struct pcicfg_standard_prop_entry {
165*26947304SEvan Yan     uchar_t *name;
166*26947304SEvan Yan     uint_t  config_offset;
167*26947304SEvan Yan     uint_t  size;
168*26947304SEvan Yan };
169*26947304SEvan Yan 
170*26947304SEvan Yan 
171*26947304SEvan Yan struct pcicfg_name_entry {
172*26947304SEvan Yan     uint32_t class_code;
173*26947304SEvan Yan     char  *name;
174*26947304SEvan Yan };
175*26947304SEvan Yan 
176*26947304SEvan Yan struct pcicfg_find_ctrl {
177*26947304SEvan Yan 	uint_t		device;
178*26947304SEvan Yan 	uint_t		function;
179*26947304SEvan Yan 	dev_info_t	*dip;
180*26947304SEvan Yan };
181*26947304SEvan Yan 
182*26947304SEvan Yan typedef struct pcicfg_err_regs {
183*26947304SEvan Yan 	uint16_t cmd;
184*26947304SEvan Yan 	uint16_t bcntl;
185*26947304SEvan Yan 	uint16_t pcie_dev;
186*26947304SEvan Yan 	uint16_t devctl;
187*26947304SEvan Yan 	uint16_t pcie_cap_off;
188*26947304SEvan Yan } pcicfg_err_regs_t;
189*26947304SEvan Yan 
190*26947304SEvan Yan /*
191*26947304SEvan Yan  * List of Indirect Config Map Devices. At least the intent of the
192*26947304SEvan Yan  * design is to look for a device in this list during the configure
193*26947304SEvan Yan  * operation, and if the device is listed here, then it is a nontransparent
194*26947304SEvan Yan  * bridge, hence load the driver and avail the config map services from
195*26947304SEvan Yan  * the driver. Class and Subclass should be as defined in the PCI specs
196*26947304SEvan Yan  * ie. class is 0x6, and subclass is 0x9.
197*26947304SEvan Yan  */
198*26947304SEvan Yan static struct {
199*26947304SEvan Yan 	uint8_t		mem_range_bar_offset;
200*26947304SEvan Yan 	uint8_t		io_range_bar_offset;
201*26947304SEvan Yan 	uint8_t		prefetch_mem_range_bar_offset;
202*26947304SEvan Yan } pcicfg_indirect_map_devs[] = {
203*26947304SEvan Yan 	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
204*26947304SEvan Yan 	0,	0,	0,
205*26947304SEvan Yan };
206*26947304SEvan Yan 
207*26947304SEvan Yan #define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
208*26947304SEvan Yan 	(\
209*26947304SEvan Yan 	((ulong_t)(busnum & 0xff) << 16)    |\
210*26947304SEvan Yan 	((ulong_t)(devnum & 0x1f) << 11)    |\
211*26947304SEvan Yan 	((ulong_t)(funcnum & 0x7) <<  8)    |\
212*26947304SEvan Yan 	((ulong_t)(register & 0x3f)))
213*26947304SEvan Yan 
214*26947304SEvan Yan /*
215*26947304SEvan Yan  * debug macros:
216*26947304SEvan Yan  */
217*26947304SEvan Yan #if	defined(DEBUG)
218*26947304SEvan Yan extern void prom_printf(const char *, ...);
219*26947304SEvan Yan 
220*26947304SEvan Yan /*
221*26947304SEvan Yan  * Following values are defined for this debug flag.
222*26947304SEvan Yan  *
223*26947304SEvan Yan  * 1 = dump configuration header only.
224*26947304SEvan Yan  * 2 = dump generic debug data only (no config header dumped)
225*26947304SEvan Yan  * 3 = dump everything (both 1 and 2)
226*26947304SEvan Yan  */
227*26947304SEvan Yan int pcicfg_debug = 0;
228*26947304SEvan Yan int pcicfg_dump_fcode = 0;
229*26947304SEvan Yan 
230*26947304SEvan Yan static void debug(char *, uintptr_t, uintptr_t,
231*26947304SEvan Yan 	uintptr_t, uintptr_t, uintptr_t);
232*26947304SEvan Yan 
233*26947304SEvan Yan #define	DEBUG0(fmt)\
234*26947304SEvan Yan 	debug(fmt, 0, 0, 0, 0, 0);
235*26947304SEvan Yan #define	DEBUG1(fmt, a1)\
236*26947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
237*26947304SEvan Yan #define	DEBUG2(fmt, a1, a2)\
238*26947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
239*26947304SEvan Yan #define	DEBUG3(fmt, a1, a2, a3)\
240*26947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
241*26947304SEvan Yan 		(uintptr_t)(a3), 0, 0);
242*26947304SEvan Yan #define	DEBUG4(fmt, a1, a2, a3, a4)\
243*26947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
244*26947304SEvan Yan 		(uintptr_t)(a3), (uintptr_t)(a4), 0);
245*26947304SEvan Yan #else
246*26947304SEvan Yan #define	DEBUG0(fmt)
247*26947304SEvan Yan #define	DEBUG1(fmt, a1)
248*26947304SEvan Yan #define	DEBUG2(fmt, a1, a2)
249*26947304SEvan Yan #define	DEBUG3(fmt, a1, a2, a3)
250*26947304SEvan Yan #define	DEBUG4(fmt, a1, a2, a3, a4)
251*26947304SEvan Yan #endif
252*26947304SEvan Yan 
253*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
254*26947304SEvan Yan int pcicfg_dont_interpret = 0;
255*26947304SEvan Yan #else
256*26947304SEvan Yan int pcicfg_dont_interpret = 1;
257*26947304SEvan Yan #endif
258*26947304SEvan Yan 
259*26947304SEvan Yan /*
260*26947304SEvan Yan  * forward declarations for routines defined in this module (called here)
261*26947304SEvan Yan  */
262*26947304SEvan Yan 
263*26947304SEvan Yan static int pcicfg_add_config_reg(dev_info_t *,
264*26947304SEvan Yan     uint_t, uint_t, uint_t);
265*26947304SEvan Yan static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
266*26947304SEvan Yan     uint_t *, pcicfg_flags_t);
267*26947304SEvan Yan 
268*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
269*26947304SEvan Yan static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
270*26947304SEvan Yan 	uint16_t, uint16_t, uchar_t **, int *, int, int);
271*26947304SEvan Yan #endif
272*26947304SEvan Yan 
273*26947304SEvan Yan static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t,
274*26947304SEvan Yan     uint_t *, pcicfg_flags_t);
275*26947304SEvan Yan static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
276*26947304SEvan Yan     uint_t *);
277*26947304SEvan Yan static int pcicfg_free_all_resources(dev_info_t *);
278*26947304SEvan Yan static int pcicfg_alloc_new_resources(dev_info_t *);
279*26947304SEvan Yan static int pcicfg_match_dev(dev_info_t *, void *);
280*26947304SEvan Yan static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
281*26947304SEvan Yan static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
282*26947304SEvan Yan static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
283*26947304SEvan Yan static int pcicfg_destroy_phdl(dev_info_t *);
284*26947304SEvan Yan static int pcicfg_sum_resources(dev_info_t *, void *);
285*26947304SEvan Yan static int pcicfg_find_resource_end(dev_info_t *, void *);
286*26947304SEvan Yan static int pcicfg_allocate_chunk(dev_info_t *);
287*26947304SEvan Yan static int pcicfg_program_ap(dev_info_t *);
288*26947304SEvan Yan static int pcicfg_device_assign(dev_info_t *);
289*26947304SEvan Yan static int pcicfg_bridge_assign(dev_info_t *, void *);
290*26947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *);
291*26947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
292*26947304SEvan Yan static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t,
293*26947304SEvan Yan     dev_info_t *);
294*26947304SEvan Yan static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
295*26947304SEvan Yan static void pcicfg_enable_bridge_probe_err(dev_info_t *dip,
296*26947304SEvan Yan 				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
297*26947304SEvan Yan static void pcicfg_disable_bridge_probe_err(dev_info_t *dip,
298*26947304SEvan Yan 				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
299*26947304SEvan Yan static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
300*26947304SEvan Yan static void pcicfg_device_on(ddi_acc_handle_t);
301*26947304SEvan Yan static void pcicfg_device_off(ddi_acc_handle_t);
302*26947304SEvan Yan static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int);
303*26947304SEvan Yan static int pcicfg_free_bridge_resources(dev_info_t *);
304*26947304SEvan Yan static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t);
305*26947304SEvan Yan static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t);
306*26947304SEvan Yan static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
307*26947304SEvan Yan static void pcicfg_config_teardown(ddi_acc_handle_t *);
308*26947304SEvan Yan static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
309*26947304SEvan Yan static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
310*26947304SEvan Yan static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *);
311*26947304SEvan Yan static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *,
312*26947304SEvan Yan     ddi_device_acc_attr_t *, ddi_acc_handle_t *);
313*26947304SEvan Yan static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
314*26947304SEvan Yan static int pcicfg_dump_assigned(dev_info_t *);
315*26947304SEvan Yan static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
316*26947304SEvan Yan static int pcicfg_indirect_map(dev_info_t *dip);
317*26947304SEvan Yan static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
318*26947304SEvan Yan 				uint64_t *, uint_t);
319*26947304SEvan Yan static int pcicfg_is_ntbridge(dev_info_t *);
320*26947304SEvan Yan static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
321*26947304SEvan Yan static int pcicfg_ntbridge_configure_done(dev_info_t *);
322*26947304SEvan Yan static int pcicfg_ntbridge_unconfigure(dev_info_t *);
323*26947304SEvan Yan static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
324*26947304SEvan Yan static void pcicfg_free_hole(hole_t *);
325*26947304SEvan Yan static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
326*26947304SEvan Yan static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *);
327*26947304SEvan Yan static int pcicfg_ari_configure(dev_info_t *);
328*26947304SEvan Yan static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
329*26947304SEvan Yan static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
330*26947304SEvan Yan static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
331*26947304SEvan Yan     uint32_t, uint32_t, uint_t);
332*26947304SEvan Yan 
333*26947304SEvan Yan #ifdef DEBUG
334*26947304SEvan Yan static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
335*26947304SEvan Yan static void pcicfg_dump_device_config(ddi_acc_handle_t);
336*26947304SEvan Yan 
337*26947304SEvan Yan static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
338*26947304SEvan Yan static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
339*26947304SEvan Yan 
340*26947304SEvan Yan #define	PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
341*26947304SEvan Yan #define	PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
342*26947304SEvan Yan #define	PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
343*26947304SEvan Yan #else
344*26947304SEvan Yan #define	PCICFG_DUMP_COMMON_CONFIG(handle)
345*26947304SEvan Yan #define	PCICFG_DUMP_DEVICE_CONFIG(handle)
346*26947304SEvan Yan #define	PCICFG_DUMP_BRIDGE_CONFIG(handle)
347*26947304SEvan Yan #endif
348*26947304SEvan Yan 
349*26947304SEvan Yan static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
350*26947304SEvan Yan static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
351*26947304SEvan Yan 
352*26947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES
353*26947304SEvan Yan /*
354*26947304SEvan Yan  * Class code table
355*26947304SEvan Yan  */
356*26947304SEvan Yan static struct pcicfg_name_entry pcicfg_class_lookup [] = {
357*26947304SEvan Yan 
358*26947304SEvan Yan 	{ 0x001, "display" },
359*26947304SEvan Yan 	{ 0x100, "scsi" },
360*26947304SEvan Yan 	{ 0x101, "ide" },
361*26947304SEvan Yan 	{ 0x102, "fdc" },
362*26947304SEvan Yan 	{ 0x103, "ipi" },
363*26947304SEvan Yan 	{ 0x104, "raid" },
364*26947304SEvan Yan 	{ 0x200, "ethernet" },
365*26947304SEvan Yan 	{ 0x201, "token-ring" },
366*26947304SEvan Yan 	{ 0x202, "fddi" },
367*26947304SEvan Yan 	{ 0x203, "atm" },
368*26947304SEvan Yan 	{ 0x300, "display" },
369*26947304SEvan Yan 	{ 0x400, "video" },
370*26947304SEvan Yan 	{ 0x401, "sound" },
371*26947304SEvan Yan 	{ 0x500, "memory" },
372*26947304SEvan Yan 	{ 0x501, "flash" },
373*26947304SEvan Yan 	{ 0x600, "host" },
374*26947304SEvan Yan 	{ 0x601, "isa" },
375*26947304SEvan Yan 	{ 0x602, "eisa" },
376*26947304SEvan Yan 	{ 0x603, "mca" },
377*26947304SEvan Yan 	{ 0x604, "pci" },
378*26947304SEvan Yan 	{ 0x605, "pcmcia" },
379*26947304SEvan Yan 	{ 0x606, "nubus" },
380*26947304SEvan Yan 	{ 0x607, "cardbus" },
381*26947304SEvan Yan 	{ 0x609, "pci" },
382*26947304SEvan Yan 	{ 0x700, "serial" },
383*26947304SEvan Yan 	{ 0x701, "parallel" },
384*26947304SEvan Yan 	{ 0x800, "interrupt-controller" },
385*26947304SEvan Yan 	{ 0x801, "dma-controller" },
386*26947304SEvan Yan 	{ 0x802, "timer" },
387*26947304SEvan Yan 	{ 0x803, "rtc" },
388*26947304SEvan Yan 	{ 0x900, "keyboard" },
389*26947304SEvan Yan 	{ 0x901, "pen" },
390*26947304SEvan Yan 	{ 0x902, "mouse" },
391*26947304SEvan Yan 	{ 0xa00, "dock" },
392*26947304SEvan Yan 	{ 0xb00, "cpu" },
393*26947304SEvan Yan 	{ 0xc00, "firewire" },
394*26947304SEvan Yan 	{ 0xc01, "access-bus" },
395*26947304SEvan Yan 	{ 0xc02, "ssa" },
396*26947304SEvan Yan 	{ 0xc03, "usb" },
397*26947304SEvan Yan 	{ 0xc04, "fibre-channel" },
398*26947304SEvan Yan 	{ 0, 0 }
399*26947304SEvan Yan };
400*26947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */
401*26947304SEvan Yan 
402*26947304SEvan Yan /*
403*26947304SEvan Yan  * Module control operations
404*26947304SEvan Yan  */
405*26947304SEvan Yan 
406*26947304SEvan Yan extern struct mod_ops mod_miscops;
407*26947304SEvan Yan 
408*26947304SEvan Yan static struct modlmisc modlmisc = {
409*26947304SEvan Yan 	&mod_miscops, /* Type of module */
410*26947304SEvan Yan 	"PCIe/PCI Config (EFCode Enabled)"
411*26947304SEvan Yan };
412*26947304SEvan Yan 
413*26947304SEvan Yan static struct modlinkage modlinkage = {
414*26947304SEvan Yan 	MODREV_1, (void *)&modlmisc, NULL
415*26947304SEvan Yan };
416*26947304SEvan Yan 
417*26947304SEvan Yan #ifdef DEBUG
418*26947304SEvan Yan 
419*26947304SEvan Yan static void
420*26947304SEvan Yan pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
421*26947304SEvan Yan {
422*26947304SEvan Yan 	if ((pcicfg_debug & 1) == 0)
423*26947304SEvan Yan 		return;
424*26947304SEvan Yan 	cmn_err(CE_CONT, " Vendor ID   = [0x%x]\n",
425*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID));
426*26947304SEvan Yan 	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
427*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
428*26947304SEvan Yan 	cmn_err(CE_CONT, " Command REG = [0x%x]\n",
429*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_COMM));
430*26947304SEvan Yan 	cmn_err(CE_CONT, " Status  REG = [0x%x]\n",
431*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_STAT));
432*26947304SEvan Yan 	cmn_err(CE_CONT, " Revision ID = [0x%x]\n",
433*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_REVID));
434*26947304SEvan Yan 	cmn_err(CE_CONT, " Prog Class  = [0x%x]\n",
435*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
436*26947304SEvan Yan 	cmn_err(CE_CONT, " Dev Class   = [0x%x]\n",
437*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
438*26947304SEvan Yan 	cmn_err(CE_CONT, " Base Class  = [0x%x]\n",
439*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
440*26947304SEvan Yan 	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
441*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
442*26947304SEvan Yan 	cmn_err(CE_CONT, " Header Type = [0x%x]\n",
443*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_HEADER));
444*26947304SEvan Yan 	cmn_err(CE_CONT, " BIST        = [0x%x]\n",
445*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_BIST));
446*26947304SEvan Yan 	cmn_err(CE_CONT, " BASE 0      = [0x%x]\n",
447*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE0));
448*26947304SEvan Yan 	cmn_err(CE_CONT, " BASE 1      = [0x%x]\n",
449*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE1));
450*26947304SEvan Yan 
451*26947304SEvan Yan }
452*26947304SEvan Yan 
453*26947304SEvan Yan static void
454*26947304SEvan Yan pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
455*26947304SEvan Yan {
456*26947304SEvan Yan 	if ((pcicfg_debug & 1) == 0)
457*26947304SEvan Yan 		return;
458*26947304SEvan Yan 	pcicfg_dump_common_config(config_handle);
459*26947304SEvan Yan 
460*26947304SEvan Yan 	cmn_err(CE_CONT, " BASE 2      = [0x%x]\n",
461*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE2));
462*26947304SEvan Yan 	cmn_err(CE_CONT, " BASE 3      = [0x%x]\n",
463*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE3));
464*26947304SEvan Yan 	cmn_err(CE_CONT, " BASE 4      = [0x%x]\n",
465*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE4));
466*26947304SEvan Yan 	cmn_err(CE_CONT, " BASE 5      = [0x%x]\n",
467*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE5));
468*26947304SEvan Yan 	cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n",
469*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_CIS));
470*26947304SEvan Yan 	cmn_err(CE_CONT, " Sub VID     = [0x%x]\n",
471*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
472*26947304SEvan Yan 	cmn_err(CE_CONT, " Sub SID     = [0x%x]\n",
473*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
474*26947304SEvan Yan 	cmn_err(CE_CONT, " ROM         = [0x%x]\n",
475*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_ROM));
476*26947304SEvan Yan 	cmn_err(CE_CONT, " I Line      = [0x%x]\n",
477*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_ILINE));
478*26947304SEvan Yan 	cmn_err(CE_CONT, " I Pin       = [0x%x]\n",
479*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_IPIN));
480*26947304SEvan Yan 	cmn_err(CE_CONT, " Max Grant   = [0x%x]\n",
481*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
482*26947304SEvan Yan 	cmn_err(CE_CONT, " Max Latent  = [0x%x]\n",
483*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
484*26947304SEvan Yan }
485*26947304SEvan Yan 
486*26947304SEvan Yan static void
487*26947304SEvan Yan pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
488*26947304SEvan Yan {
489*26947304SEvan Yan 	if ((pcicfg_debug & 1) == 0)
490*26947304SEvan Yan 		return;
491*26947304SEvan Yan 
492*26947304SEvan Yan 	pcicfg_dump_common_config(config_handle);
493*26947304SEvan Yan 
494*26947304SEvan Yan 	cmn_err(CE_CONT, "........................................\n");
495*26947304SEvan Yan 
496*26947304SEvan Yan 	cmn_err(CE_CONT, " Pri Bus     = [0x%x]\n",
497*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
498*26947304SEvan Yan 	cmn_err(CE_CONT, " Sec Bus     = [0x%x]\n",
499*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
500*26947304SEvan Yan 	cmn_err(CE_CONT, " Sub Bus     = [0x%x]\n",
501*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
502*26947304SEvan Yan 	cmn_err(CE_CONT, " Latency     = [0x%x]\n",
503*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
504*26947304SEvan Yan 	cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n",
505*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
506*26947304SEvan Yan 	cmn_err(CE_CONT, " I/O Lim LO  = [0x%x]\n",
507*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
508*26947304SEvan Yan 	cmn_err(CE_CONT, " Sec. Status = [0x%x]\n",
509*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
510*26947304SEvan Yan 	cmn_err(CE_CONT, " Mem Base    = [0x%x]\n",
511*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
512*26947304SEvan Yan 	cmn_err(CE_CONT, " Mem Limit   = [0x%x]\n",
513*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
514*26947304SEvan Yan 	cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n",
515*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
516*26947304SEvan Yan 	cmn_err(CE_CONT, " PF Mem Lim  = [0x%x]\n",
517*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
518*26947304SEvan Yan 	cmn_err(CE_CONT, " PF Base HI  = [0x%x]\n",
519*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
520*26947304SEvan Yan 	cmn_err(CE_CONT, " PF Lim  HI  = [0x%x]\n",
521*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
522*26947304SEvan Yan 	cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n",
523*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
524*26947304SEvan Yan 	cmn_err(CE_CONT, " I/O Lim HI  = [0x%x]\n",
525*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
526*26947304SEvan Yan 	cmn_err(CE_CONT, " ROM addr    = [0x%x]\n",
527*26947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_ROM));
528*26947304SEvan Yan 	cmn_err(CE_CONT, " Intr Line   = [0x%x]\n",
529*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
530*26947304SEvan Yan 	cmn_err(CE_CONT, " Intr Pin    = [0x%x]\n",
531*26947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
532*26947304SEvan Yan 	cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n",
533*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
534*26947304SEvan Yan }
535*26947304SEvan Yan 
536*26947304SEvan Yan #endif
537*26947304SEvan Yan 
538*26947304SEvan Yan 
539*26947304SEvan Yan int
540*26947304SEvan Yan _init()
541*26947304SEvan Yan {
542*26947304SEvan Yan 	DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n");
543*26947304SEvan Yan 
544*26947304SEvan Yan 	mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
545*26947304SEvan Yan 	return (mod_install(&modlinkage));
546*26947304SEvan Yan }
547*26947304SEvan Yan 
548*26947304SEvan Yan int
549*26947304SEvan Yan _fini(void)
550*26947304SEvan Yan {
551*26947304SEvan Yan 	int error;
552*26947304SEvan Yan 
553*26947304SEvan Yan 	error = mod_remove(&modlinkage);
554*26947304SEvan Yan 	if (error != 0) {
555*26947304SEvan Yan 		return (error);
556*26947304SEvan Yan 	}
557*26947304SEvan Yan 	mutex_destroy(&pcicfg_list_mutex);
558*26947304SEvan Yan 	return (0);
559*26947304SEvan Yan }
560*26947304SEvan Yan 
561*26947304SEvan Yan int
562*26947304SEvan Yan _info(modinfop)
563*26947304SEvan Yan struct modinfo *modinfop;
564*26947304SEvan Yan {
565*26947304SEvan Yan 	return (mod_info(&modlinkage, modinfop));
566*26947304SEvan Yan }
567*26947304SEvan Yan 
568*26947304SEvan Yan /*ARGSUSED*/
569*26947304SEvan Yan static uint8_t
570*26947304SEvan Yan pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
571*26947304SEvan Yan {
572*26947304SEvan Yan 	uint8_t num_slots = 0;
573*26947304SEvan Yan 	uint16_t cap_ptr;
574*26947304SEvan Yan 
575*26947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG,
576*26947304SEvan Yan 	    &cap_ptr)) == DDI_SUCCESS) {
577*26947304SEvan Yan 		uint32_t config;
578*26947304SEvan Yan 
579*26947304SEvan Yan 		PCI_CAP_PUT8(handle, NULL, cap_ptr, PCI_HP_DWORD_SELECT_OFF,
580*26947304SEvan Yan 		    PCI_HP_SLOT_CONFIGURATION_REG);
581*26947304SEvan Yan 		config = PCI_CAP_GET32(handle, NULL, cap_ptr,
582*26947304SEvan Yan 		    PCI_HP_DWORD_DATA_OFF);
583*26947304SEvan Yan 		num_slots = config & 0x1F;
584*26947304SEvan Yan 	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr))
585*26947304SEvan Yan 	    == DDI_SUCCESS) {
586*26947304SEvan Yan 		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL,
587*26947304SEvan Yan 		    cap_ptr, PCI_CAP_ID_REGS_OFF);
588*26947304SEvan Yan 
589*26947304SEvan Yan 		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
590*26947304SEvan Yan 	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
591*26947304SEvan Yan 	    == DDI_SUCCESS) {
592*26947304SEvan Yan 		int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr,
593*26947304SEvan Yan 		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
594*26947304SEvan Yan 
595*26947304SEvan Yan 		if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) &&
596*26947304SEvan Yan 		    (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP)
597*26947304SEvan Yan 		    & PCIE_PCIECAP_SLOT_IMPL))
598*26947304SEvan Yan 				num_slots = 1;
599*26947304SEvan Yan 	}
600*26947304SEvan Yan 
601*26947304SEvan Yan 	DEBUG3("%s#%d has %d slots",
602*26947304SEvan Yan 	    ddi_get_name(dip), ddi_get_instance(dip), num_slots);
603*26947304SEvan Yan 
604*26947304SEvan Yan 	return (num_slots);
605*26947304SEvan Yan }
606*26947304SEvan Yan 
607*26947304SEvan Yan /*ARGSUSED*/
608*26947304SEvan Yan static uint8_t
609*26947304SEvan Yan pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle)
610*26947304SEvan Yan {
611*26947304SEvan Yan 	uint16_t cap_ptr;
612*26947304SEvan Yan 
613*26947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) !=
614*26947304SEvan Yan 	    DDI_FAILURE) {
615*26947304SEvan Yan 
616*26947304SEvan Yan 		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2);
617*26947304SEvan Yan 		if (PCI_CAPSLOT_FIC(esr_reg))
618*26947304SEvan Yan 			return (B_TRUE);
619*26947304SEvan Yan 	}
620*26947304SEvan Yan 	return (B_FALSE);
621*26947304SEvan Yan }
622*26947304SEvan Yan 
623*26947304SEvan Yan /*ARGSUSED*/
624*26947304SEvan Yan static int
625*26947304SEvan Yan pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs)
626*26947304SEvan Yan {
627*26947304SEvan Yan 	/* get parent device's device_type property */
628*26947304SEvan Yan 	char *device_type;
629*26947304SEvan Yan 	int rc = DDI_FAILURE;
630*26947304SEvan Yan 	dev_info_t *pdip = ddi_get_parent(dip);
631*26947304SEvan Yan 
632*26947304SEvan Yan 	regs->pcie_dev = 0;
633*26947304SEvan Yan 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
634*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "device_type", &device_type)
635*26947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
636*26947304SEvan Yan 		DEBUG2("device_type property missing for %s#%d",
637*26947304SEvan Yan 		    ddi_get_name(pdip), ddi_get_instance(pdip));
638*26947304SEvan Yan 		return (DDI_FAILURE);
639*26947304SEvan Yan 	}
640*26947304SEvan Yan 	switch (bus_type) {
641*26947304SEvan Yan 		case PCICFG_DEVICE_TYPE_PCIE:
642*26947304SEvan Yan 			if (strcmp(device_type, "pciex") == 0) {
643*26947304SEvan Yan 				rc = DDI_SUCCESS;
644*26947304SEvan Yan 				regs->pcie_dev = 1;
645*26947304SEvan Yan 			}
646*26947304SEvan Yan 			break;
647*26947304SEvan Yan 		case PCICFG_DEVICE_TYPE_PCI:
648*26947304SEvan Yan 			if (strcmp(device_type, "pci") == 0)
649*26947304SEvan Yan 				rc = DDI_SUCCESS;
650*26947304SEvan Yan 			break;
651*26947304SEvan Yan 		default:
652*26947304SEvan Yan 			break;
653*26947304SEvan Yan 	}
654*26947304SEvan Yan 	ddi_prop_free(device_type);
655*26947304SEvan Yan 	return (rc);
656*26947304SEvan Yan }
657*26947304SEvan Yan 
658*26947304SEvan Yan /*ARGSUSED*/
659*26947304SEvan Yan static int
660*26947304SEvan Yan pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
661*26947304SEvan Yan {
662*26947304SEvan Yan 	int port_type = -1;
663*26947304SEvan Yan 	uint16_t cap_ptr;
664*26947304SEvan Yan 
665*26947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
666*26947304SEvan Yan 	    DDI_FAILURE)
667*26947304SEvan Yan 		port_type = PCI_CAP_GET16(handle, NULL,
668*26947304SEvan Yan 		    cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
669*26947304SEvan Yan 
670*26947304SEvan Yan 	return (port_type);
671*26947304SEvan Yan }
672*26947304SEvan Yan 
673*26947304SEvan Yan static int
674*26947304SEvan Yan pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
675*26947304SEvan Yan {
676*26947304SEvan Yan 	int port_type = pcicfg_pcie_port_type(dip, handle);
677*26947304SEvan Yan 
678*26947304SEvan Yan 	DEBUG1("device port_type = %x\n", port_type);
679*26947304SEvan Yan 	/* No PCIe CAP regs, we are not PCIe device_type */
680*26947304SEvan Yan 	if (port_type < 0)
681*26947304SEvan Yan 		return (DDI_FAILURE);
682*26947304SEvan Yan 
683*26947304SEvan Yan 	/* check for all PCIe device_types */
684*26947304SEvan Yan 	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
685*26947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
686*26947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
687*26947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
688*26947304SEvan Yan 		return (DDI_SUCCESS);
689*26947304SEvan Yan 
690*26947304SEvan Yan 	return (DDI_FAILURE);
691*26947304SEvan Yan 
692*26947304SEvan Yan }
693*26947304SEvan Yan 
694*26947304SEvan Yan /*
695*26947304SEvan Yan  * In the following functions ndi_devi_enter() without holding the
696*26947304SEvan Yan  * parent dip is sufficient. This is because  pci dr is driven through
697*26947304SEvan Yan  * opens on the nexus which is in the device tree path above the node
698*26947304SEvan Yan  * being operated on, and implicitly held due to the open.
699*26947304SEvan Yan  */
700*26947304SEvan Yan 
701*26947304SEvan Yan /*
702*26947304SEvan Yan  * This entry point is called to configure a device (and
703*26947304SEvan Yan  * all its children) on the given bus. It is called when
704*26947304SEvan Yan  * a new device is added to the PCI domain.  This routine
705*26947304SEvan Yan  * will create the device tree and program the devices
706*26947304SEvan Yan  * registers.
707*26947304SEvan Yan  */
708*26947304SEvan Yan 
709*26947304SEvan Yan int
710*26947304SEvan Yan pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
711*26947304SEvan Yan     pcicfg_flags_t flags)
712*26947304SEvan Yan {
713*26947304SEvan Yan 	uint_t bus;
714*26947304SEvan Yan 	int len;
715*26947304SEvan Yan 	int func;
716*26947304SEvan Yan 	int trans_device;
717*26947304SEvan Yan 	dev_info_t *new_device;
718*26947304SEvan Yan 	pcicfg_bus_range_t pci_bus_range;
719*26947304SEvan Yan 	int rv;
720*26947304SEvan Yan 	int circ;
721*26947304SEvan Yan 	uint_t highest_bus = 0;
722*26947304SEvan Yan 	int ari_mode = B_FALSE;
723*26947304SEvan Yan 	int max_function = PCICFG_MAX_FUNCTION;
724*26947304SEvan Yan 
725*26947304SEvan Yan 	if (flags == PCICFG_FLAG_ENABLE_ARI)
726*26947304SEvan Yan 		return (pcicfg_ari_configure(devi));
727*26947304SEvan Yan 
728*26947304SEvan Yan 	/*
729*26947304SEvan Yan 	 * Start probing at the device specified in "device" on the
730*26947304SEvan Yan 	 * "bus" specified.
731*26947304SEvan Yan 	 */
732*26947304SEvan Yan 	len = sizeof (pcicfg_bus_range_t);
733*26947304SEvan Yan 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
734*26947304SEvan Yan 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
735*26947304SEvan Yan 		DEBUG0("no bus-range property\n");
736*26947304SEvan Yan 		return (PCICFG_FAILURE);
737*26947304SEvan Yan 	}
738*26947304SEvan Yan 
739*26947304SEvan Yan 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
740*26947304SEvan Yan 
741*26947304SEvan Yan 	ndi_devi_enter(devi, &circ);
742*26947304SEvan Yan 	for (func = 0; func < max_function; ) {
743*26947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
744*26947304SEvan Yan 			goto next;
745*26947304SEvan Yan 
746*26947304SEvan Yan 		if (ari_mode)
747*26947304SEvan Yan 			trans_device = func >> 3;
748*26947304SEvan Yan 		else
749*26947304SEvan Yan 			trans_device = device;
750*26947304SEvan Yan 
751*26947304SEvan Yan 		DEBUG3("Configuring [0x%x][0x%x][0x%x]\n",
752*26947304SEvan Yan 		    bus, trans_device, func & 7);
753*26947304SEvan Yan 
754*26947304SEvan Yan 		/*
755*26947304SEvan Yan 		 * Try executing fcode if available.
756*26947304SEvan Yan 		 */
757*26947304SEvan Yan 		switch (rv = pcicfg_fcode_probe(devi, bus, trans_device,
758*26947304SEvan Yan 		    func & 7, &highest_bus, flags)) {
759*26947304SEvan Yan 			case PCICFG_FAILURE:
760*26947304SEvan Yan 				DEBUG2("configure failed: "
761*26947304SEvan Yan 				    "bus [0x%x] device [0x%x]\n",
762*26947304SEvan Yan 				    bus, trans_device);
763*26947304SEvan Yan 				break;
764*26947304SEvan Yan 			case PCICFG_NODEVICE:
765*26947304SEvan Yan 				DEBUG3("no device : bus "
766*26947304SEvan Yan 				    "[0x%x] slot [0x%x] func [0x%x]\n",
767*26947304SEvan Yan 				    bus, trans_device, func & 7);
768*26947304SEvan Yan 				if (func)
769*26947304SEvan Yan 					goto next;
770*26947304SEvan Yan 				break;
771*26947304SEvan Yan 			default:
772*26947304SEvan Yan 				DEBUG3("configure: bus => [%d] "
773*26947304SEvan Yan 				    "slot => [%d] func => [%d]\n",
774*26947304SEvan Yan 				    bus, trans_device, func & 7);
775*26947304SEvan Yan 				break;
776*26947304SEvan Yan 		}
777*26947304SEvan Yan 
778*26947304SEvan Yan 		if (rv != PCICFG_SUCCESS)
779*26947304SEvan Yan 			break;
780*26947304SEvan Yan 
781*26947304SEvan Yan 		if ((new_device = pcicfg_devi_find(devi,
782*26947304SEvan Yan 		    trans_device, (func & 7))) == NULL) {
783*26947304SEvan Yan 			DEBUG0("Did'nt find device node just created\n");
784*26947304SEvan Yan 			goto cleanup;
785*26947304SEvan Yan 		}
786*26947304SEvan Yan 
787*26947304SEvan Yan next:
788*26947304SEvan Yan 		/*
789*26947304SEvan Yan 		 * Determine if ARI Forwarding should be enabled.
790*26947304SEvan Yan 		 */
791*26947304SEvan Yan 		if (func == 0) {
792*26947304SEvan Yan 			if ((pcie_ari_supported(devi)
793*26947304SEvan Yan 			    == PCIE_ARI_FORW_SUPPORTED) &&
794*26947304SEvan Yan 			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
795*26947304SEvan Yan 				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
796*26947304SEvan Yan 					(void) ddi_prop_create(DDI_DEV_T_NONE,
797*26947304SEvan Yan 					    devi,  DDI_PROP_CANSLEEP,
798*26947304SEvan Yan 					    "ari-enabled", NULL, 0);
799*26947304SEvan Yan 
800*26947304SEvan Yan 					ari_mode = B_TRUE;
801*26947304SEvan Yan 					max_function = PCICFG_MAX_ARI_FUNCTION;
802*26947304SEvan Yan 				}
803*26947304SEvan Yan 			}
804*26947304SEvan Yan 		}
805*26947304SEvan Yan 
806*26947304SEvan Yan 		if (ari_mode == B_TRUE) {
807*26947304SEvan Yan 			int next_function;
808*26947304SEvan Yan 
809*26947304SEvan Yan 			DEBUG0("Next Function - ARI Device\n");
810*26947304SEvan Yan 			if (pcie_ari_get_next_function(new_device,
811*26947304SEvan Yan 			    &next_function) != DDI_SUCCESS)
812*26947304SEvan Yan 				goto cleanup;
813*26947304SEvan Yan 
814*26947304SEvan Yan 			/*
815*26947304SEvan Yan 			 * Check if there are more fucntions to probe.
816*26947304SEvan Yan 			 */
817*26947304SEvan Yan 			if (next_function == 0) {
818*26947304SEvan Yan 				DEBUG0("Next Function - "
819*26947304SEvan Yan 				    "No more ARI Functions\n");
820*26947304SEvan Yan 				break;
821*26947304SEvan Yan 			}
822*26947304SEvan Yan 			func = next_function;
823*26947304SEvan Yan 		} else {
824*26947304SEvan Yan 			func++;
825*26947304SEvan Yan 		}
826*26947304SEvan Yan 
827*26947304SEvan Yan 		DEBUG1("Next Function - %x\n", func);
828*26947304SEvan Yan 	}
829*26947304SEvan Yan 
830*26947304SEvan Yan 	ndi_devi_exit(devi, circ);
831*26947304SEvan Yan 
832*26947304SEvan Yan 	if (func == 0)
833*26947304SEvan Yan 		return (PCICFG_FAILURE);	/* probe failed */
834*26947304SEvan Yan 	else
835*26947304SEvan Yan 		return (PCICFG_SUCCESS);
836*26947304SEvan Yan 
837*26947304SEvan Yan cleanup:
838*26947304SEvan Yan 	/*
839*26947304SEvan Yan 	 * Clean up a partially created "probe state" tree.
840*26947304SEvan Yan 	 * There are no resources allocated to the in the
841*26947304SEvan Yan 	 * probe state.
842*26947304SEvan Yan 	 */
843*26947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
844*26947304SEvan Yan 		max_function = PCICFG_MAX_ARI_FUNCTION;
845*26947304SEvan Yan 	else
846*26947304SEvan Yan 		max_function = PCICFG_MAX_FUNCTION;
847*26947304SEvan Yan 
848*26947304SEvan Yan 	for (func = 0; func < max_function; func++) {
849*26947304SEvan Yan 
850*26947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
851*26947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
852*26947304SEvan Yan 		else
853*26947304SEvan Yan 			trans_device = device;
854*26947304SEvan Yan 
855*26947304SEvan Yan 		if ((new_device = pcicfg_devi_find(devi,
856*26947304SEvan Yan 		    trans_device, (func & 0x7))) == NULL) {
857*26947304SEvan Yan 			DEBUG0("No more devices to clean up\n");
858*26947304SEvan Yan 			continue;
859*26947304SEvan Yan 		}
860*26947304SEvan Yan 
861*26947304SEvan Yan 		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
862*26947304SEvan Yan 		    trans_device, func & 7);
863*26947304SEvan Yan 		/*
864*26947304SEvan Yan 		 * If this was a bridge device it will have a
865*26947304SEvan Yan 		 * probe handle - if not, no harm in calling this.
866*26947304SEvan Yan 		 */
867*26947304SEvan Yan 		(void) pcicfg_destroy_phdl(new_device);
868*26947304SEvan Yan 		/*
869*26947304SEvan Yan 		 * This will free up the node
870*26947304SEvan Yan 		 */
871*26947304SEvan Yan 		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
872*26947304SEvan Yan 	}
873*26947304SEvan Yan 	ndi_devi_exit(devi, circ);
874*26947304SEvan Yan 
875*26947304SEvan Yan 	return (PCICFG_FAILURE);
876*26947304SEvan Yan }
877*26947304SEvan Yan 
878*26947304SEvan Yan /*
879*26947304SEvan Yan  * configure the child nodes of ntbridge. new_device points to ntbridge itself
880*26947304SEvan Yan  */
881*26947304SEvan Yan /*ARGSUSED*/
882*26947304SEvan Yan static uint_t
883*26947304SEvan Yan pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
884*26947304SEvan Yan {
885*26947304SEvan Yan 	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
886*26947304SEvan Yan 	int			devno;
887*26947304SEvan Yan 	dev_info_t		*new_ntbridgechild;
888*26947304SEvan Yan 	ddi_acc_handle_t	config_handle;
889*26947304SEvan Yan 	uint16_t		vid;
890*26947304SEvan Yan 	uint64_t		next_bus;
891*26947304SEvan Yan 	uint64_t		blen;
892*26947304SEvan Yan 	ndi_ra_request_t	req;
893*26947304SEvan Yan 	uint8_t			pcie_device_type = 0;
894*26947304SEvan Yan 
895*26947304SEvan Yan 	/*
896*26947304SEvan Yan 	 * If we need to do indirect config, lets create a property here
897*26947304SEvan Yan 	 * to let the child conf map routine know that it has to
898*26947304SEvan Yan 	 * go through the DDI calls, and not assume the devices are
899*26947304SEvan Yan 	 * mapped directly under the host.
900*26947304SEvan Yan 	 */
901*26947304SEvan Yan 	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
902*26947304SEvan Yan 	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
903*26947304SEvan Yan 	    != DDI_SUCCESS) {
904*26947304SEvan Yan 
905*26947304SEvan Yan 		DEBUG0("Cannot create indirect conf map property.\n");
906*26947304SEvan Yan 		return ((uint_t)PCICFG_FAILURE);
907*26947304SEvan Yan 	}
908*26947304SEvan Yan 	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
909*26947304SEvan Yan 		return ((uint_t)PCICFG_FAILURE);
910*26947304SEvan Yan 	/* check if we are PCIe device */
911*26947304SEvan Yan 	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS)
912*26947304SEvan Yan 		pcie_device_type = 1;
913*26947304SEvan Yan 	pci_config_teardown(&config_handle);
914*26947304SEvan Yan 
915*26947304SEvan Yan 	/* create Bus node properties for ntbridge. */
916*26947304SEvan Yan 	if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) !=
917*26947304SEvan Yan 	    PCICFG_SUCCESS) {
918*26947304SEvan Yan 		DEBUG0("Failed to set busnode props\n");
919*26947304SEvan Yan 		return (rc);
920*26947304SEvan Yan 	}
921*26947304SEvan Yan 
922*26947304SEvan Yan 	/* For now: Lets only support one layer of child */
923*26947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
924*26947304SEvan Yan 	req.ra_len = 1;
925*26947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(new_device), &req,
926*26947304SEvan Yan 	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
927*26947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
928*26947304SEvan Yan 		DEBUG0("ntbridge: Failed to get a bus number\n");
929*26947304SEvan Yan 		return (rc);
930*26947304SEvan Yan 	}
931*26947304SEvan Yan 
932*26947304SEvan Yan 	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
933*26947304SEvan Yan 
934*26947304SEvan Yan 	/*
935*26947304SEvan Yan 	 * Following will change, as we detect more bridges
936*26947304SEvan Yan 	 * on the way.
937*26947304SEvan Yan 	 */
938*26947304SEvan Yan 	bus_range[0] = (int)next_bus;
939*26947304SEvan Yan 	bus_range[1] = (int)next_bus;
940*26947304SEvan Yan 
941*26947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device,
942*26947304SEvan Yan 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
943*26947304SEvan Yan 		DEBUG0("Cannot set ntbridge bus-range property");
944*26947304SEvan Yan 		return (rc);
945*26947304SEvan Yan 	}
946*26947304SEvan Yan 
947*26947304SEvan Yan 	/*
948*26947304SEvan Yan 	 * The other interface (away from the host) will be
949*26947304SEvan Yan 	 * initialized by the nexus driver when it loads.
950*26947304SEvan Yan 	 * We just have to set the registers and the nexus driver
951*26947304SEvan Yan 	 * figures out the rest.
952*26947304SEvan Yan 	 */
953*26947304SEvan Yan 
954*26947304SEvan Yan 	/*
955*26947304SEvan Yan 	 * finally, lets load and attach the driver
956*26947304SEvan Yan 	 * before configuring children of ntbridge.
957*26947304SEvan Yan 	 */
958*26947304SEvan Yan 	rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG);
959*26947304SEvan Yan 	if (rc != NDI_SUCCESS) {
960*26947304SEvan Yan 		cmn_err(CE_WARN,
961*26947304SEvan Yan 		    "pcicfg: Fail: can\'t load non-transparent bridge \
962*26947304SEvan Yan 		    driver.\n");
963*26947304SEvan Yan 		rc = PCICFG_FAILURE;
964*26947304SEvan Yan 		return (rc);
965*26947304SEvan Yan 	}
966*26947304SEvan Yan 	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
967*26947304SEvan Yan 
968*26947304SEvan Yan 	/* Now set aside pci resources for our children. */
969*26947304SEvan Yan 	if (pcicfg_ntbridge_allocate_resources(new_device) !=
970*26947304SEvan Yan 	    PCICFG_SUCCESS) {
971*26947304SEvan Yan 		max_devs = 0;
972*26947304SEvan Yan 		rc = PCICFG_FAILURE;
973*26947304SEvan Yan 	} else
974*26947304SEvan Yan 		max_devs = PCICFG_MAX_DEVICE;
975*26947304SEvan Yan 
976*26947304SEvan Yan 	/* Probe devices on 2nd bus */
977*26947304SEvan Yan 	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
978*26947304SEvan Yan 
979*26947304SEvan Yan 		if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
980*26947304SEvan Yan 		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild)
981*26947304SEvan Yan 		    != NDI_SUCCESS) {
982*26947304SEvan Yan 
983*26947304SEvan Yan 			DEBUG0("pcicfg: Failed to alloc test node\n");
984*26947304SEvan Yan 			rc = PCICFG_FAILURE;
985*26947304SEvan Yan 			break;
986*26947304SEvan Yan 		}
987*26947304SEvan Yan 
988*26947304SEvan Yan 		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
989*26947304SEvan Yan 		    != DDI_PROP_SUCCESS) {
990*26947304SEvan Yan 			cmn_err(CE_WARN,
991*26947304SEvan Yan 			    "Failed to add conf reg for ntbridge child.\n");
992*26947304SEvan Yan 			(void) ndi_devi_free(new_ntbridgechild);
993*26947304SEvan Yan 			rc = PCICFG_FAILURE;
994*26947304SEvan Yan 			break;
995*26947304SEvan Yan 		}
996*26947304SEvan Yan 
997*26947304SEvan Yan 		if ((rc = pci_config_setup(new_ntbridgechild,
998*26947304SEvan Yan 		    &config_handle)) != PCICFG_SUCCESS) {
999*26947304SEvan Yan 			cmn_err(CE_WARN,
1000*26947304SEvan Yan 			    "Cannot map ntbridge child %x\n", devno);
1001*26947304SEvan Yan 			(void) ndi_devi_free(new_ntbridgechild);
1002*26947304SEvan Yan 			rc = PCICFG_FAILURE;
1003*26947304SEvan Yan 			break;
1004*26947304SEvan Yan 		}
1005*26947304SEvan Yan 
1006*26947304SEvan Yan 		/*
1007*26947304SEvan Yan 		 * See if there is any PCI HW at this location
1008*26947304SEvan Yan 		 * by reading the Vendor ID.  If it returns with 0xffff
1009*26947304SEvan Yan 		 * then there is no hardware at this location.
1010*26947304SEvan Yan 		 */
1011*26947304SEvan Yan 		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
1012*26947304SEvan Yan 
1013*26947304SEvan Yan 		pci_config_teardown(&config_handle);
1014*26947304SEvan Yan 		(void) ndi_devi_free(new_ntbridgechild);
1015*26947304SEvan Yan 		if (vid	== 0xffff)
1016*26947304SEvan Yan 			continue;
1017*26947304SEvan Yan 
1018*26947304SEvan Yan 		/* Lets fake attachments points for each child, */
1019*26947304SEvan Yan 		if (pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0)
1020*26947304SEvan Yan 		    != PCICFG_SUCCESS) {
1021*26947304SEvan Yan 			int old_dev = pcicfg_start_devno;
1022*26947304SEvan Yan 
1023*26947304SEvan Yan 			cmn_err(CE_WARN,
1024*26947304SEvan Yan 			"Error configuring ntbridge child dev=%d\n", devno);
1025*26947304SEvan Yan 
1026*26947304SEvan Yan 			rc = PCICFG_FAILURE;
1027*26947304SEvan Yan 			while (old_dev != devno) {
1028*26947304SEvan Yan 				if (pcicfg_ntbridge_unconfigure_child(
1029*26947304SEvan Yan 				    new_device, old_dev) == PCICFG_FAILURE)
1030*26947304SEvan Yan 
1031*26947304SEvan Yan 					cmn_err(CE_WARN,
1032*26947304SEvan Yan 					    "Unconfig Error ntbridge child "
1033*26947304SEvan Yan 					    "dev=%d\n", old_dev);
1034*26947304SEvan Yan 				old_dev++;
1035*26947304SEvan Yan 			}
1036*26947304SEvan Yan 			break;
1037*26947304SEvan Yan 		}
1038*26947304SEvan Yan 	} /* devno loop */
1039*26947304SEvan Yan 	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
1040*26947304SEvan Yan 
1041*26947304SEvan Yan 	if (rc != PCICFG_FAILURE)
1042*26947304SEvan Yan 		rc = pcicfg_ntbridge_configure_done(new_device);
1043*26947304SEvan Yan 	else {
1044*26947304SEvan Yan 		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
1045*26947304SEvan Yan 		uint_t			*bus;
1046*26947304SEvan Yan 		int			k;
1047*26947304SEvan Yan 
1048*26947304SEvan Yan 		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
1049*26947304SEvan Yan 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
1050*26947304SEvan Yan 		    &k) != DDI_PROP_SUCCESS) {
1051*26947304SEvan Yan 			DEBUG0("Failed to read bus-range property\n");
1052*26947304SEvan Yan 			rc = PCICFG_FAILURE;
1053*26947304SEvan Yan 			return (rc);
1054*26947304SEvan Yan 		}
1055*26947304SEvan Yan 
1056*26947304SEvan Yan 		DEBUG2("Need to free bus [%d] range [%d]\n",
1057*26947304SEvan Yan 		    bus[0], bus[1] - bus[0] + 1);
1058*26947304SEvan Yan 
1059*26947304SEvan Yan 		if (ndi_ra_free(ddi_get_parent(new_device),
1060*26947304SEvan Yan 		    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
1061*26947304SEvan Yan 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
1062*26947304SEvan Yan 			DEBUG0("Failed to free a bus number\n");
1063*26947304SEvan Yan 			rc = PCICFG_FAILURE;
1064*26947304SEvan Yan 			/*
1065*26947304SEvan Yan 			 * Don't forget to free up memory from ddi_getlongprop
1066*26947304SEvan Yan 			 */
1067*26947304SEvan Yan 			kmem_free((caddr_t)bus, k);
1068*26947304SEvan Yan 
1069*26947304SEvan Yan 			return (rc);
1070*26947304SEvan Yan 		}
1071*26947304SEvan Yan 
1072*26947304SEvan Yan 		/*
1073*26947304SEvan Yan 		 * Since no memory allocations are done for non transparent
1074*26947304SEvan Yan 		 * bridges (but instead we just set the handle with the
1075*26947304SEvan Yan 		 * already allocated memory, we just need to reset the
1076*26947304SEvan Yan 		 * following values before calling the destroy_phdl()
1077*26947304SEvan Yan 		 * function next, otherwise the it will try to free
1078*26947304SEvan Yan 		 * memory allocated as in case of a transparent bridge.
1079*26947304SEvan Yan 		 */
1080*26947304SEvan Yan 		entry->memory_len = 0;
1081*26947304SEvan Yan 		entry->io_len = 0;
1082*26947304SEvan Yan 		/* the following will free hole data. */
1083*26947304SEvan Yan 		(void) pcicfg_destroy_phdl(new_device);
1084*26947304SEvan Yan 		/*
1085*26947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
1086*26947304SEvan Yan 		 */
1087*26947304SEvan Yan 		kmem_free((caddr_t)bus, k);
1088*26947304SEvan Yan 	}
1089*26947304SEvan Yan 
1090*26947304SEvan Yan 	/*
1091*26947304SEvan Yan 	 * Unload driver just in case child configure failed!
1092*26947304SEvan Yan 	 */
1093*26947304SEvan Yan 	rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT);
1094*26947304SEvan Yan 	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
1095*26947304SEvan Yan 	if (rc1 != NDI_SUCCESS) {
1096*26947304SEvan Yan 		cmn_err(CE_WARN,
1097*26947304SEvan Yan 		    "pcicfg: can\'t unload ntbridge driver children.\n");
1098*26947304SEvan Yan 		rc = PCICFG_FAILURE;
1099*26947304SEvan Yan 	}
1100*26947304SEvan Yan 
1101*26947304SEvan Yan 	return (rc);
1102*26947304SEvan Yan }
1103*26947304SEvan Yan 
1104*26947304SEvan Yan static int
1105*26947304SEvan Yan pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
1106*26947304SEvan Yan {
1107*26947304SEvan Yan 	pcicfg_phdl_t		*phdl;
1108*26947304SEvan Yan 	ndi_ra_request_t	*mem_request;
1109*26947304SEvan Yan 	ndi_ra_request_t	*io_request;
1110*26947304SEvan Yan 	uint64_t		boundbase, boundlen;
1111*26947304SEvan Yan 
1112*26947304SEvan Yan 	phdl = pcicfg_find_phdl(dip);
1113*26947304SEvan Yan 	ASSERT(phdl);
1114*26947304SEvan Yan 
1115*26947304SEvan Yan 	mem_request = &phdl->mem_req;
1116*26947304SEvan Yan 	io_request  = &phdl->io_req;
1117*26947304SEvan Yan 
1118*26947304SEvan Yan 	phdl->error = PCICFG_SUCCESS;
1119*26947304SEvan Yan 
1120*26947304SEvan Yan 	/* Set Memory space handle for ntbridge */
1121*26947304SEvan Yan 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
1122*26947304SEvan Yan 	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
1123*26947304SEvan Yan 		cmn_err(CE_WARN,
1124*26947304SEvan Yan 		    "ntbridge: Mem resource information failure\n");
1125*26947304SEvan Yan 		phdl->memory_len  = 0;
1126*26947304SEvan Yan 		return (PCICFG_FAILURE);
1127*26947304SEvan Yan 	}
1128*26947304SEvan Yan 	mem_request->ra_boundbase = boundbase;
1129*26947304SEvan Yan 	mem_request->ra_boundlen = boundbase + boundlen;
1130*26947304SEvan Yan 	mem_request->ra_len = boundlen;
1131*26947304SEvan Yan 	mem_request->ra_align_mask =
1132*26947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
1133*26947304SEvan Yan 	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
1134*26947304SEvan Yan 
1135*26947304SEvan Yan 	/*
1136*26947304SEvan Yan 	 * mem_request->ra_len =
1137*26947304SEvan Yan 	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
1138*26947304SEvan Yan 	 */
1139*26947304SEvan Yan 
1140*26947304SEvan Yan 	phdl->memory_base = phdl->memory_last = boundbase;
1141*26947304SEvan Yan 	phdl->memory_len  = boundlen;
1142*26947304SEvan Yan 	phdl->mem_hole.start = phdl->memory_base;
1143*26947304SEvan Yan 	phdl->mem_hole.len = mem_request->ra_len;
1144*26947304SEvan Yan 	phdl->mem_hole.next = (hole_t *)NULL;
1145*26947304SEvan Yan 
1146*26947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
1147*26947304SEvan Yan 	    boundlen, mem_request->ra_len);
1148*26947304SEvan Yan 
1149*26947304SEvan Yan 	/* set up a memory resource map for NT bridge */
1150*26947304SEvan Yan 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
1151*26947304SEvan Yan 		DEBUG0("Can not setup ntbridge memory resource map\n");
1152*26947304SEvan Yan 		return (PCICFG_FAILURE);
1153*26947304SEvan Yan 	}
1154*26947304SEvan Yan 	/* initialize the memory map */
1155*26947304SEvan Yan 	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM,
1156*26947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
1157*26947304SEvan Yan 		DEBUG0("Can not initalize ntbridge memory resource map\n");
1158*26947304SEvan Yan 		return (PCICFG_FAILURE);
1159*26947304SEvan Yan 	}
1160*26947304SEvan Yan 	/* Set IO space handle for ntbridge */
1161*26947304SEvan Yan 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
1162*26947304SEvan Yan 	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
1163*26947304SEvan Yan 		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
1164*26947304SEvan Yan 		phdl->io_len  = 0;
1165*26947304SEvan Yan 		return (PCICFG_FAILURE);
1166*26947304SEvan Yan 	}
1167*26947304SEvan Yan 	io_request->ra_len = boundlen;
1168*26947304SEvan Yan 	io_request->ra_align_mask =
1169*26947304SEvan Yan 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
1170*26947304SEvan Yan 	io_request->ra_boundbase = boundbase;
1171*26947304SEvan Yan 	io_request->ra_boundlen = boundbase + boundlen;
1172*26947304SEvan Yan 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
1173*26947304SEvan Yan 
1174*26947304SEvan Yan 	/*
1175*26947304SEvan Yan 	 * io_request->ra_len =
1176*26947304SEvan Yan 	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
1177*26947304SEvan Yan 	 */
1178*26947304SEvan Yan 
1179*26947304SEvan Yan 	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
1180*26947304SEvan Yan 	phdl->io_len  = (uint32_t)boundlen;
1181*26947304SEvan Yan 	phdl->io_hole.start = phdl->io_base;
1182*26947304SEvan Yan 	phdl->io_hole.len = io_request->ra_len;
1183*26947304SEvan Yan 	phdl->io_hole.next = (hole_t *)NULL;
1184*26947304SEvan Yan 
1185*26947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
1186*26947304SEvan Yan 	    boundlen, io_request->ra_len);
1187*26947304SEvan Yan 
1188*26947304SEvan Yan 	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
1189*26947304SEvan Yan 	    phdl->memory_base, phdl->memory_len);
1190*26947304SEvan Yan 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
1191*26947304SEvan Yan 	    phdl->io_base, phdl->io_len);
1192*26947304SEvan Yan 
1193*26947304SEvan Yan 	/* set up a IO resource map for NT bridge */
1194*26947304SEvan Yan 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
1195*26947304SEvan Yan 		DEBUG0("Can not setup ntbridge memory resource map\n");
1196*26947304SEvan Yan 		return (PCICFG_FAILURE);
1197*26947304SEvan Yan 	}
1198*26947304SEvan Yan 	/* initialize the IO map */
1199*26947304SEvan Yan 	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO,
1200*26947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
1201*26947304SEvan Yan 		DEBUG0("Can not initalize ntbridge memory resource map\n");
1202*26947304SEvan Yan 		return (PCICFG_FAILURE);
1203*26947304SEvan Yan 	}
1204*26947304SEvan Yan 
1205*26947304SEvan Yan 	return (PCICFG_SUCCESS);
1206*26947304SEvan Yan }
1207*26947304SEvan Yan 
1208*26947304SEvan Yan static int
1209*26947304SEvan Yan pcicfg_ntbridge_configure_done(dev_info_t *dip)
1210*26947304SEvan Yan {
1211*26947304SEvan Yan 	pcicfg_range_t range[PCICFG_RANGE_LEN];
1212*26947304SEvan Yan 	pcicfg_phdl_t		*entry;
1213*26947304SEvan Yan 	uint_t			len;
1214*26947304SEvan Yan 	pcicfg_bus_range_t	bus_range;
1215*26947304SEvan Yan 	int			new_bus_range[2];
1216*26947304SEvan Yan 
1217*26947304SEvan Yan 	DEBUG1("Configuring children for %llx\n", dip);
1218*26947304SEvan Yan 
1219*26947304SEvan Yan 	entry = pcicfg_find_phdl(dip);
1220*26947304SEvan Yan 	ASSERT(entry);
1221*26947304SEvan Yan 
1222*26947304SEvan Yan 	bzero((caddr_t)range,
1223*26947304SEvan Yan 	    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
1224*26947304SEvan Yan 	range[1].child_hi = range[1].parent_hi |=
1225*26947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
1226*26947304SEvan Yan 	range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base;
1227*26947304SEvan Yan 
1228*26947304SEvan Yan 	range[0].child_hi = range[0].parent_hi |=
1229*26947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_IO);
1230*26947304SEvan Yan 	range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base;
1231*26947304SEvan Yan 
1232*26947304SEvan Yan 	len = sizeof (pcicfg_bus_range_t);
1233*26947304SEvan Yan 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1234*26947304SEvan Yan 	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
1235*26947304SEvan Yan 		DEBUG0("no bus-range property\n");
1236*26947304SEvan Yan 		return (PCICFG_FAILURE);
1237*26947304SEvan Yan 	}
1238*26947304SEvan Yan 
1239*26947304SEvan Yan 	new_bus_range[0] = bus_range.lo;	/* primary bus number */
1240*26947304SEvan Yan 	if (entry->highest_bus) {	/* secondary bus number */
1241*26947304SEvan Yan 		if (entry->highest_bus < bus_range.lo) {
1242*26947304SEvan Yan 			cmn_err(CE_WARN,
1243*26947304SEvan Yan 			    "ntbridge bus range invalid !(%d,%d)\n",
1244*26947304SEvan Yan 			    bus_range.lo, entry->highest_bus);
1245*26947304SEvan Yan 			new_bus_range[1] = bus_range.lo + entry->highest_bus;
1246*26947304SEvan Yan 		}
1247*26947304SEvan Yan 		else
1248*26947304SEvan Yan 			new_bus_range[1] = entry->highest_bus;
1249*26947304SEvan Yan 	}
1250*26947304SEvan Yan 	else
1251*26947304SEvan Yan 		new_bus_range[1] = bus_range.hi;
1252*26947304SEvan Yan 
1253*26947304SEvan Yan 	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n",
1254*26947304SEvan Yan 	    new_bus_range[0], new_bus_range[1]);
1255*26947304SEvan Yan 
1256*26947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1257*26947304SEvan Yan 	    "bus-range", new_bus_range, 2) != DDI_SUCCESS) {
1258*26947304SEvan Yan 		DEBUG0("Failed to set bus-range property");
1259*26947304SEvan Yan 		entry->error = PCICFG_FAILURE;
1260*26947304SEvan Yan 		return (PCICFG_FAILURE);
1261*26947304SEvan Yan 	}
1262*26947304SEvan Yan 
1263*26947304SEvan Yan #ifdef DEBUG
1264*26947304SEvan Yan 	{
1265*26947304SEvan Yan 		uint64_t	unused;
1266*26947304SEvan Yan 		unused = pcicfg_unused_space(&entry->io_hole, &len);
1267*26947304SEvan Yan 		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
1268*26947304SEvan Yan 		    unused, len);
1269*26947304SEvan Yan 	}
1270*26947304SEvan Yan #endif
1271*26947304SEvan Yan 
1272*26947304SEvan Yan 	range[0].size_lo = entry->io_len;
1273*26947304SEvan Yan 	if (pcicfg_update_ranges_prop(dip, &range[0])) {
1274*26947304SEvan Yan 		DEBUG0("Failed to update ranges (i/o)\n");
1275*26947304SEvan Yan 		entry->error = PCICFG_FAILURE;
1276*26947304SEvan Yan 		return (PCICFG_FAILURE);
1277*26947304SEvan Yan 	}
1278*26947304SEvan Yan 
1279*26947304SEvan Yan #ifdef DEBUG
1280*26947304SEvan Yan 	{
1281*26947304SEvan Yan 		uint64_t	unused;
1282*26947304SEvan Yan 		unused = pcicfg_unused_space(&entry->mem_hole, &len);
1283*26947304SEvan Yan 		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
1284*26947304SEvan Yan 		    unused, len);
1285*26947304SEvan Yan 	}
1286*26947304SEvan Yan #endif
1287*26947304SEvan Yan 
1288*26947304SEvan Yan 	range[1].size_lo = entry->memory_len;
1289*26947304SEvan Yan 	if (pcicfg_update_ranges_prop(dip, &range[1])) {
1290*26947304SEvan Yan 		DEBUG0("Failed to update ranges (memory)\n");
1291*26947304SEvan Yan 		entry->error = PCICFG_FAILURE;
1292*26947304SEvan Yan 		return (PCICFG_FAILURE);
1293*26947304SEvan Yan 	}
1294*26947304SEvan Yan 
1295*26947304SEvan Yan 	return (PCICFG_SUCCESS);
1296*26947304SEvan Yan }
1297*26947304SEvan Yan 
1298*26947304SEvan Yan static int
1299*26947304SEvan Yan pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
1300*26947304SEvan Yan {
1301*26947304SEvan Yan 
1302*26947304SEvan Yan 	dev_info_t	*new_ntbridgechild;
1303*26947304SEvan Yan 	int 		len, bus;
1304*26947304SEvan Yan 	uint16_t	vid;
1305*26947304SEvan Yan 	ddi_acc_handle_t	config_handle;
1306*26947304SEvan Yan 	pcicfg_bus_range_t pci_bus_range;
1307*26947304SEvan Yan 
1308*26947304SEvan Yan 	len = sizeof (pcicfg_bus_range_t);
1309*26947304SEvan Yan 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
1310*26947304SEvan Yan 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
1311*26947304SEvan Yan 		DEBUG0("no bus-range property\n");
1312*26947304SEvan Yan 		return (PCICFG_FAILURE);
1313*26947304SEvan Yan 	}
1314*26947304SEvan Yan 
1315*26947304SEvan Yan 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
1316*26947304SEvan Yan 
1317*26947304SEvan Yan 	if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
1318*26947304SEvan Yan 	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) {
1319*26947304SEvan Yan 
1320*26947304SEvan Yan 		DEBUG0("pcicfg: Failed to alloc test node\n");
1321*26947304SEvan Yan 		return (PCICFG_FAILURE);
1322*26947304SEvan Yan 	}
1323*26947304SEvan Yan 
1324*26947304SEvan Yan 	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
1325*26947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
1326*26947304SEvan Yan 		cmn_err(CE_WARN,
1327*26947304SEvan Yan 		"Unconfigure: Failed to add conf reg prop for ntbridge "
1328*26947304SEvan Yan 		    "child.\n");
1329*26947304SEvan Yan 		(void) ndi_devi_free(new_ntbridgechild);
1330*26947304SEvan Yan 		return (PCICFG_FAILURE);
1331*26947304SEvan Yan 	}
1332*26947304SEvan Yan 
1333*26947304SEvan Yan 	if (pcicfg_config_setup(new_ntbridgechild, &config_handle)
1334*26947304SEvan Yan 	    != DDI_SUCCESS) {
1335*26947304SEvan Yan 		cmn_err(CE_WARN,
1336*26947304SEvan Yan 		    "pcicfg: Cannot map ntbridge child %x\n", devno);
1337*26947304SEvan Yan 		(void) ndi_devi_free(new_ntbridgechild);
1338*26947304SEvan Yan 		return (PCICFG_FAILURE);
1339*26947304SEvan Yan 	}
1340*26947304SEvan Yan 
1341*26947304SEvan Yan 	/*
1342*26947304SEvan Yan 	 * See if there is any PCI HW at this location
1343*26947304SEvan Yan 	 * by reading the Vendor ID.  If it returns with 0xffff
1344*26947304SEvan Yan 	 * then there is no hardware at this location.
1345*26947304SEvan Yan 	 */
1346*26947304SEvan Yan 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
1347*26947304SEvan Yan 
1348*26947304SEvan Yan 	pci_config_teardown(&config_handle);
1349*26947304SEvan Yan 	(void) ndi_devi_free(new_ntbridgechild);
1350*26947304SEvan Yan 	if (vid	== 0xffff)
1351*26947304SEvan Yan 		return (PCICFG_NODEVICE);
1352*26947304SEvan Yan 
1353*26947304SEvan Yan 	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
1354*26947304SEvan Yan }
1355*26947304SEvan Yan 
1356*26947304SEvan Yan static int
1357*26947304SEvan Yan pcicfg_ntbridge_unconfigure(dev_info_t *dip)
1358*26947304SEvan Yan {
1359*26947304SEvan Yan 	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
1360*26947304SEvan Yan 	uint_t			*bus;
1361*26947304SEvan Yan 	int			k, rc = PCICFG_FAILURE;
1362*26947304SEvan Yan 
1363*26947304SEvan Yan 	if (entry->memory_len)
1364*26947304SEvan Yan 		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
1365*26947304SEvan Yan 			DEBUG1("cannot destroy ntbridge memory map size=%x\n",
1366*26947304SEvan Yan 			    entry->memory_len);
1367*26947304SEvan Yan 			return (PCICFG_FAILURE);
1368*26947304SEvan Yan 		}
1369*26947304SEvan Yan 	if (entry->io_len)
1370*26947304SEvan Yan 		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
1371*26947304SEvan Yan 			DEBUG1("cannot destroy ntbridge io map size=%x\n",
1372*26947304SEvan Yan 			    entry->io_len);
1373*26947304SEvan Yan 			return (PCICFG_FAILURE);
1374*26947304SEvan Yan 		}
1375*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
1376*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
1377*26947304SEvan Yan 	    &k) != DDI_PROP_SUCCESS) {
1378*26947304SEvan Yan 		DEBUG0("ntbridge: Failed to read bus-range property\n");
1379*26947304SEvan Yan 		return (rc);
1380*26947304SEvan Yan 	}
1381*26947304SEvan Yan 
1382*26947304SEvan Yan 	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
1383*26947304SEvan Yan 	    bus[0], bus[1] - bus[0] + 1);
1384*26947304SEvan Yan 
1385*26947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip),
1386*26947304SEvan Yan 	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
1387*26947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
1388*26947304SEvan Yan 		DEBUG0("ntbridge: Failed to free a bus number\n");
1389*26947304SEvan Yan 		/*
1390*26947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
1391*26947304SEvan Yan 		 */
1392*26947304SEvan Yan 		kmem_free((caddr_t)bus, k);
1393*26947304SEvan Yan 
1394*26947304SEvan Yan 		return (rc);
1395*26947304SEvan Yan 	}
1396*26947304SEvan Yan 
1397*26947304SEvan Yan 	/*
1398*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
1399*26947304SEvan Yan 	 */
1400*26947304SEvan Yan 	kmem_free((caddr_t)bus, k);
1401*26947304SEvan Yan 
1402*26947304SEvan Yan 	/*
1403*26947304SEvan Yan 	 * Since our resources will be freed at the parent level,
1404*26947304SEvan Yan 	 * just reset these values.
1405*26947304SEvan Yan 	 */
1406*26947304SEvan Yan 	entry->memory_len = 0;
1407*26947304SEvan Yan 	entry->io_len = 0;
1408*26947304SEvan Yan 	/* the following will also free hole data. */
1409*26947304SEvan Yan 	return (pcicfg_destroy_phdl(dip));
1410*26947304SEvan Yan 
1411*26947304SEvan Yan }
1412*26947304SEvan Yan 
1413*26947304SEvan Yan static int
1414*26947304SEvan Yan pcicfg_is_ntbridge(dev_info_t *dip)
1415*26947304SEvan Yan {
1416*26947304SEvan Yan 	ddi_acc_handle_t	config_handle;
1417*26947304SEvan Yan 	uint8_t		class, subclass;
1418*26947304SEvan Yan 	int		rc = DDI_SUCCESS;
1419*26947304SEvan Yan 
1420*26947304SEvan Yan 	if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) {
1421*26947304SEvan Yan 		cmn_err(CE_WARN,
1422*26947304SEvan Yan 		    "pcicfg: cannot map config space, to get map type\n");
1423*26947304SEvan Yan 		return (DDI_FAILURE);
1424*26947304SEvan Yan 	}
1425*26947304SEvan Yan 	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
1426*26947304SEvan Yan 	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
1427*26947304SEvan Yan 
1428*26947304SEvan Yan 	/* check for class=6, subclass=9, for non transparent bridges.  */
1429*26947304SEvan Yan 	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
1430*26947304SEvan Yan 		rc = DDI_FAILURE;
1431*26947304SEvan Yan 
1432*26947304SEvan Yan 	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
1433*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID),
1434*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID),
1435*26947304SEvan Yan 	    rc);
1436*26947304SEvan Yan 	pci_config_teardown(&config_handle);
1437*26947304SEvan Yan 	return (rc);
1438*26947304SEvan Yan }
1439*26947304SEvan Yan 
1440*26947304SEvan Yan /*
1441*26947304SEvan Yan  * this function is called only for SPARC platforms, where we may have
1442*26947304SEvan Yan  * a mix n' match of direct vs indirectly mapped configuration space.
1443*26947304SEvan Yan  * On x86, this function does not get called. We always return TRUE
1444*26947304SEvan Yan  * via a macro for x86.
1445*26947304SEvan Yan  */
1446*26947304SEvan Yan /*ARGSUSED*/
1447*26947304SEvan Yan static int
1448*26947304SEvan Yan pcicfg_indirect_map(dev_info_t *dip)
1449*26947304SEvan Yan {
1450*26947304SEvan Yan #if defined(__sparc)
1451*26947304SEvan Yan 	int rc = DDI_FAILURE;
1452*26947304SEvan Yan 
1453*26947304SEvan Yan 	if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
1454*26947304SEvan Yan 	    PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
1455*26947304SEvan Yan 		rc = DDI_SUCCESS;
1456*26947304SEvan Yan 	else
1457*26947304SEvan Yan 		if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
1458*26947304SEvan Yan 		    0, PCI_BUS_CONF_MAP_PROP,
1459*26947304SEvan Yan 		    DDI_FAILURE) != DDI_FAILURE)
1460*26947304SEvan Yan 			rc = DDI_SUCCESS;
1461*26947304SEvan Yan 	DEBUG1("pci conf map = %d", rc);
1462*26947304SEvan Yan 	return (rc);
1463*26947304SEvan Yan #else
1464*26947304SEvan Yan 	return (DDI_SUCCESS);
1465*26947304SEvan Yan #endif
1466*26947304SEvan Yan }
1467*26947304SEvan Yan 
1468*26947304SEvan Yan static uint_t
1469*26947304SEvan Yan pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
1470*26947304SEvan Yan 				uint64_t *boundlen, uint_t space_type)
1471*26947304SEvan Yan {
1472*26947304SEvan Yan 	int		length, found = DDI_FAILURE, acount, i, ibridge;
1473*26947304SEvan Yan 	pci_regspec_t	*assigned;
1474*26947304SEvan Yan 
1475*26947304SEvan Yan 	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
1476*26947304SEvan Yan 		return (found);
1477*26947304SEvan Yan 
1478*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
1479*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
1480*26947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
1481*26947304SEvan Yan 		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
1482*26947304SEvan Yan 		return (found);
1483*26947304SEvan Yan 	}
1484*26947304SEvan Yan 	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
1485*26947304SEvan Yan 	    ddi_driver_name(dip));
1486*26947304SEvan Yan 
1487*26947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
1488*26947304SEvan Yan 
1489*26947304SEvan Yan 	for (i = 0; i < acount; i++) {
1490*26947304SEvan Yan 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
1491*26947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
1492*26947304SEvan Yan 		    (space_type == PCI_BASE_SPACE_MEM)) {
1493*26947304SEvan Yan 			found = DDI_SUCCESS;
1494*26947304SEvan Yan 			break;
1495*26947304SEvan Yan 		} else {
1496*26947304SEvan Yan 			if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
1497*26947304SEvan Yan 			    pcicfg_indirect_map_devs[ibridge].\
1498*26947304SEvan Yan 			    io_range_bar_offset) &&
1499*26947304SEvan Yan 			    (space_type == PCI_BASE_SPACE_IO)) {
1500*26947304SEvan Yan 				found = DDI_SUCCESS;
1501*26947304SEvan Yan 				break;
1502*26947304SEvan Yan 			}
1503*26947304SEvan Yan 		}
1504*26947304SEvan Yan 	}
1505*26947304SEvan Yan 	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
1506*26947304SEvan Yan 	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
1507*26947304SEvan Yan 
1508*26947304SEvan Yan 	if (found == DDI_SUCCESS)  {
1509*26947304SEvan Yan 		*boundbase = assigned[i].pci_phys_low;
1510*26947304SEvan Yan 		*boundlen = assigned[i].pci_size_low;
1511*26947304SEvan Yan 	}
1512*26947304SEvan Yan 
1513*26947304SEvan Yan 	kmem_free(assigned, length);
1514*26947304SEvan Yan 	return (found);
1515*26947304SEvan Yan }
1516*26947304SEvan Yan 
1517*26947304SEvan Yan /*
1518*26947304SEvan Yan  * This will turn  resources allocated by pcicfg_configure()
1519*26947304SEvan Yan  * and remove the device tree from the Hotplug Connection (CN)
1520*26947304SEvan Yan  * and below.  The routine assumes the devices have their
1521*26947304SEvan Yan  * drivers detached.
1522*26947304SEvan Yan  */
1523*26947304SEvan Yan int
1524*26947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
1525*26947304SEvan Yan     pcicfg_flags_t flags)
1526*26947304SEvan Yan {
1527*26947304SEvan Yan 	dev_info_t *child_dip;
1528*26947304SEvan Yan 	int func;
1529*26947304SEvan Yan 	int i;
1530*26947304SEvan Yan 	int max_function;
1531*26947304SEvan Yan 	int trans_device;
1532*26947304SEvan Yan 
1533*26947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
1534*26947304SEvan Yan 		max_function = PCICFG_MAX_ARI_FUNCTION;
1535*26947304SEvan Yan 	else
1536*26947304SEvan Yan 		max_function = PCICFG_MAX_FUNCTION;
1537*26947304SEvan Yan 
1538*26947304SEvan Yan 	/*
1539*26947304SEvan Yan 	 * Cycle through devices to make sure none are busy.
1540*26947304SEvan Yan 	 * If a single device is busy fail the whole unconfigure.
1541*26947304SEvan Yan 	 */
1542*26947304SEvan Yan 	for (func = 0; func < max_function; func++) {
1543*26947304SEvan Yan 
1544*26947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
1545*26947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
1546*26947304SEvan Yan 		else
1547*26947304SEvan Yan 			trans_device = device;
1548*26947304SEvan Yan 
1549*26947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device,
1550*26947304SEvan Yan 		    (func & 0x7))) == NULL)
1551*26947304SEvan Yan 			continue;
1552*26947304SEvan Yan 
1553*26947304SEvan Yan 		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
1554*26947304SEvan Yan 			continue;
1555*26947304SEvan Yan 		/*
1556*26947304SEvan Yan 		 * Device function is busy. Before returning we have to
1557*26947304SEvan Yan 		 * put all functions back online which were taken
1558*26947304SEvan Yan 		 * offline during the process.
1559*26947304SEvan Yan 		 */
1560*26947304SEvan Yan 		DEBUG2("Device [0x%x] function [%x] is busy\n", device, func);
1561*26947304SEvan Yan 		/*
1562*26947304SEvan Yan 		 * If we are only asked to offline one specific function,
1563*26947304SEvan Yan 		 * and that fails, we just simply return.
1564*26947304SEvan Yan 		 */
1565*26947304SEvan Yan 		if (function != PCICFG_ALL_FUNC)
1566*26947304SEvan Yan 			return (PCICFG_FAILURE);
1567*26947304SEvan Yan 
1568*26947304SEvan Yan 		for (i = 0; i < func; i++) {
1569*26947304SEvan Yan 
1570*26947304SEvan Yan 			if (max_function == PCICFG_MAX_ARI_FUNCTION)
1571*26947304SEvan Yan 				trans_device = i >> 3;
1572*26947304SEvan Yan 
1573*26947304SEvan Yan 			if ((child_dip =
1574*26947304SEvan Yan 			    pcicfg_devi_find(devi, trans_device, (i & 7)))
1575*26947304SEvan Yan 			    == NULL) {
1576*26947304SEvan Yan 				DEBUG0(
1577*26947304SEvan Yan 				    "No more devices to put back on line!!\n");
1578*26947304SEvan Yan 				/*
1579*26947304SEvan Yan 				 * Made it through all functions
1580*26947304SEvan Yan 				 */
1581*26947304SEvan Yan 				continue;
1582*26947304SEvan Yan 			}
1583*26947304SEvan Yan 			if (ndi_devi_online(child_dip, NDI_CONFIG)
1584*26947304SEvan Yan 			    != NDI_SUCCESS) {
1585*26947304SEvan Yan 				DEBUG0("Failed to put back devices state\n");
1586*26947304SEvan Yan 				return (PCICFG_FAILURE);
1587*26947304SEvan Yan 			}
1588*26947304SEvan Yan 		}
1589*26947304SEvan Yan 		return (PCICFG_FAILURE);
1590*26947304SEvan Yan 	}
1591*26947304SEvan Yan 
1592*26947304SEvan Yan 	/*
1593*26947304SEvan Yan 	 * Now, tear down all devinfo nodes for this Connector.
1594*26947304SEvan Yan 	 */
1595*26947304SEvan Yan 	for (func = 0; func < max_function; func++) {
1596*26947304SEvan Yan 
1597*26947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
1598*26947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
1599*26947304SEvan Yan 		else
1600*26947304SEvan Yan 			trans_device = device;
1601*26947304SEvan Yan 
1602*26947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi,
1603*26947304SEvan Yan 		    trans_device, (func & 7))) == NULL) {
1604*26947304SEvan Yan 			DEBUG0("No more devices to tear down!\n");
1605*26947304SEvan Yan 			continue;
1606*26947304SEvan Yan 		}
1607*26947304SEvan Yan 
1608*26947304SEvan Yan 		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
1609*26947304SEvan Yan 		    trans_device, (func & 7));
1610*26947304SEvan Yan 
1611*26947304SEvan Yan 		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
1612*26947304SEvan Yan 			if (pcicfg_ntbridge_unconfigure(child_dip) !=
1613*26947304SEvan Yan 			    PCICFG_SUCCESS) {
1614*26947304SEvan Yan 				cmn_err(CE_WARN,
1615*26947304SEvan Yan 				    "ntbridge: unconfigure failed\n");
1616*26947304SEvan Yan 				return (PCICFG_FAILURE);
1617*26947304SEvan Yan 			}
1618*26947304SEvan Yan 
1619*26947304SEvan Yan 		if (pcicfg_teardown_device(child_dip, flags)
1620*26947304SEvan Yan 		    != PCICFG_SUCCESS) {
1621*26947304SEvan Yan 			DEBUG2("Failed to tear down device [0x%x]"
1622*26947304SEvan Yan 			    "function [0x%x]\n",
1623*26947304SEvan Yan 			    trans_device, func & 7);
1624*26947304SEvan Yan 			return (PCICFG_FAILURE);
1625*26947304SEvan Yan 		}
1626*26947304SEvan Yan 	}
1627*26947304SEvan Yan 
1628*26947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
1629*26947304SEvan Yan 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
1630*26947304SEvan Yan 		(void) pcie_ari_disable(devi);
1631*26947304SEvan Yan 	}
1632*26947304SEvan Yan 
1633*26947304SEvan Yan 	return (PCICFG_SUCCESS);
1634*26947304SEvan Yan }
1635*26947304SEvan Yan 
1636*26947304SEvan Yan static int
1637*26947304SEvan Yan pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags)
1638*26947304SEvan Yan {
1639*26947304SEvan Yan 	ddi_acc_handle_t	config_handle;
1640*26947304SEvan Yan 
1641*26947304SEvan Yan 	/*
1642*26947304SEvan Yan 	 * Free up resources associated with 'dip'
1643*26947304SEvan Yan 	 */
1644*26947304SEvan Yan 	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
1645*26947304SEvan Yan 		DEBUG0("Failed to free resources\n");
1646*26947304SEvan Yan 		return (PCICFG_FAILURE);
1647*26947304SEvan Yan 	}
1648*26947304SEvan Yan 
1649*26947304SEvan Yan 	/*
1650*26947304SEvan Yan 	 * This will disable the device
1651*26947304SEvan Yan 	 */
1652*26947304SEvan Yan 	if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) {
1653*26947304SEvan Yan 		return (PCICFG_FAILURE);
1654*26947304SEvan Yan 	}
1655*26947304SEvan Yan 
1656*26947304SEvan Yan 	pcicfg_device_off(config_handle);
1657*26947304SEvan Yan 	pci_config_teardown(&config_handle);
1658*26947304SEvan Yan 
1659*26947304SEvan Yan 	/*
1660*26947304SEvan Yan 	 * The framework provides this routine which can
1661*26947304SEvan Yan 	 * tear down a sub-tree.
1662*26947304SEvan Yan 	 */
1663*26947304SEvan Yan 	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
1664*26947304SEvan Yan 		DEBUG0("Failed to offline and remove node\n");
1665*26947304SEvan Yan 		return (PCICFG_FAILURE);
1666*26947304SEvan Yan 	}
1667*26947304SEvan Yan 
1668*26947304SEvan Yan 	return (PCICFG_SUCCESS);
1669*26947304SEvan Yan }
1670*26947304SEvan Yan 
1671*26947304SEvan Yan /*
1672*26947304SEvan Yan  * BEGIN GENERIC SUPPORT ROUTINES
1673*26947304SEvan Yan  */
1674*26947304SEvan Yan static pcicfg_phdl_t *
1675*26947304SEvan Yan pcicfg_find_phdl(dev_info_t *dip)
1676*26947304SEvan Yan {
1677*26947304SEvan Yan 	pcicfg_phdl_t *entry;
1678*26947304SEvan Yan 	mutex_enter(&pcicfg_list_mutex);
1679*26947304SEvan Yan 	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
1680*26947304SEvan Yan 		if (entry->dip == dip) {
1681*26947304SEvan Yan 			mutex_exit(&pcicfg_list_mutex);
1682*26947304SEvan Yan 			return (entry);
1683*26947304SEvan Yan 		}
1684*26947304SEvan Yan 	}
1685*26947304SEvan Yan 	mutex_exit(&pcicfg_list_mutex);
1686*26947304SEvan Yan 
1687*26947304SEvan Yan 	/*
1688*26947304SEvan Yan 	 * Did'nt find entry - create one
1689*26947304SEvan Yan 	 */
1690*26947304SEvan Yan 	return (pcicfg_create_phdl(dip));
1691*26947304SEvan Yan }
1692*26947304SEvan Yan 
1693*26947304SEvan Yan static pcicfg_phdl_t *
1694*26947304SEvan Yan pcicfg_create_phdl(dev_info_t *dip)
1695*26947304SEvan Yan {
1696*26947304SEvan Yan 	pcicfg_phdl_t *new;
1697*26947304SEvan Yan 
1698*26947304SEvan Yan 	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t),
1699*26947304SEvan Yan 	    KM_SLEEP);
1700*26947304SEvan Yan 
1701*26947304SEvan Yan 	new->dip = dip;
1702*26947304SEvan Yan 	mutex_enter(&pcicfg_list_mutex);
1703*26947304SEvan Yan 	new->next = pcicfg_phdl_list;
1704*26947304SEvan Yan 	pcicfg_phdl_list = new;
1705*26947304SEvan Yan 	mutex_exit(&pcicfg_list_mutex);
1706*26947304SEvan Yan 
1707*26947304SEvan Yan 	return (new);
1708*26947304SEvan Yan }
1709*26947304SEvan Yan 
1710*26947304SEvan Yan static int
1711*26947304SEvan Yan pcicfg_destroy_phdl(dev_info_t *dip)
1712*26947304SEvan Yan {
1713*26947304SEvan Yan 	pcicfg_phdl_t *entry;
1714*26947304SEvan Yan 	pcicfg_phdl_t *follow = NULL;
1715*26947304SEvan Yan 
1716*26947304SEvan Yan 	mutex_enter(&pcicfg_list_mutex);
1717*26947304SEvan Yan 	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
1718*26947304SEvan Yan 	    entry = entry->next) {
1719*26947304SEvan Yan 		if (entry->dip == dip) {
1720*26947304SEvan Yan 			if (entry == pcicfg_phdl_list) {
1721*26947304SEvan Yan 				pcicfg_phdl_list = entry->next;
1722*26947304SEvan Yan 			} else {
1723*26947304SEvan Yan 				follow->next = entry->next;
1724*26947304SEvan Yan 			}
1725*26947304SEvan Yan 			/*
1726*26947304SEvan Yan 			 * If this entry has any allocated memory
1727*26947304SEvan Yan 			 * or IO space associated with it, that
1728*26947304SEvan Yan 			 * must be freed up.
1729*26947304SEvan Yan 			 */
1730*26947304SEvan Yan 			if (entry->memory_len > 0) {
1731*26947304SEvan Yan 				(void) ndi_ra_free(ddi_get_parent(dip),
1732*26947304SEvan Yan 				    entry->memory_base,
1733*26947304SEvan Yan 				    entry->memory_len,
1734*26947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
1735*26947304SEvan Yan 			}
1736*26947304SEvan Yan 			pcicfg_free_hole(&entry->mem_hole);
1737*26947304SEvan Yan 
1738*26947304SEvan Yan 			if (entry->io_len > 0) {
1739*26947304SEvan Yan 				(void) ndi_ra_free(ddi_get_parent(dip),
1740*26947304SEvan Yan 				    entry->io_base,
1741*26947304SEvan Yan 				    entry->io_len,
1742*26947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS);
1743*26947304SEvan Yan 			}
1744*26947304SEvan Yan 			pcicfg_free_hole(&entry->io_hole);
1745*26947304SEvan Yan 
1746*26947304SEvan Yan 			/*
1747*26947304SEvan Yan 			 * Destroy this entry
1748*26947304SEvan Yan 			 */
1749*26947304SEvan Yan 			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
1750*26947304SEvan Yan 			mutex_exit(&pcicfg_list_mutex);
1751*26947304SEvan Yan 			return (PCICFG_SUCCESS);
1752*26947304SEvan Yan 		}
1753*26947304SEvan Yan 	}
1754*26947304SEvan Yan 	mutex_exit(&pcicfg_list_mutex);
1755*26947304SEvan Yan 	/*
1756*26947304SEvan Yan 	 * Did'nt find the entry
1757*26947304SEvan Yan 	 */
1758*26947304SEvan Yan 	return (PCICFG_FAILURE);
1759*26947304SEvan Yan }
1760*26947304SEvan Yan 
1761*26947304SEvan Yan static int
1762*26947304SEvan Yan pcicfg_program_ap(dev_info_t *dip)
1763*26947304SEvan Yan {
1764*26947304SEvan Yan 	pcicfg_phdl_t *phdl;
1765*26947304SEvan Yan 	uint8_t header_type;
1766*26947304SEvan Yan 	ddi_acc_handle_t handle;
1767*26947304SEvan Yan 	pcicfg_phdl_t *entry;
1768*26947304SEvan Yan 
1769*26947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
1770*26947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
1771*26947304SEvan Yan 		return (PCICFG_FAILURE);
1772*26947304SEvan Yan 
1773*26947304SEvan Yan 	}
1774*26947304SEvan Yan 
1775*26947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
1776*26947304SEvan Yan 
1777*26947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
1778*26947304SEvan Yan 
1779*26947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
1780*26947304SEvan Yan 
1781*26947304SEvan Yan 		if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) {
1782*26947304SEvan Yan 			DEBUG0("Not enough memory to hotplug\n");
1783*26947304SEvan Yan 			(void) pcicfg_destroy_phdl(dip);
1784*26947304SEvan Yan 			return (PCICFG_FAILURE);
1785*26947304SEvan Yan 		}
1786*26947304SEvan Yan 
1787*26947304SEvan Yan 		phdl = pcicfg_find_phdl(dip);
1788*26947304SEvan Yan 		ASSERT(phdl);
1789*26947304SEvan Yan 
1790*26947304SEvan Yan 		(void) pcicfg_bridge_assign(dip, (void *)phdl);
1791*26947304SEvan Yan 
1792*26947304SEvan Yan 		if (phdl->error != PCICFG_SUCCESS) {
1793*26947304SEvan Yan 			DEBUG0("Problem assigning bridge\n");
1794*26947304SEvan Yan 			(void) pcicfg_destroy_phdl(dip);
1795*26947304SEvan Yan 			return (phdl->error);
1796*26947304SEvan Yan 		}
1797*26947304SEvan Yan 
1798*26947304SEvan Yan 		/*
1799*26947304SEvan Yan 		 * Successfully allocated and assigned
1800*26947304SEvan Yan 		 * memory.  Set the memory and IO length
1801*26947304SEvan Yan 		 * to zero so when the handle is freed up
1802*26947304SEvan Yan 		 * it will not de-allocate assigned resources.
1803*26947304SEvan Yan 		 */
1804*26947304SEvan Yan 		entry = (pcicfg_phdl_t *)phdl;
1805*26947304SEvan Yan 
1806*26947304SEvan Yan 		entry->memory_len = entry->io_len = 0;
1807*26947304SEvan Yan 
1808*26947304SEvan Yan 		/*
1809*26947304SEvan Yan 		 * Free up the "entry" structure.
1810*26947304SEvan Yan 		 */
1811*26947304SEvan Yan 		(void) pcicfg_destroy_phdl(dip);
1812*26947304SEvan Yan 	} else {
1813*26947304SEvan Yan 		if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) {
1814*26947304SEvan Yan 			return (PCICFG_FAILURE);
1815*26947304SEvan Yan 		}
1816*26947304SEvan Yan 	}
1817*26947304SEvan Yan 	return (PCICFG_SUCCESS);
1818*26947304SEvan Yan }
1819*26947304SEvan Yan 
1820*26947304SEvan Yan static int
1821*26947304SEvan Yan pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
1822*26947304SEvan Yan {
1823*26947304SEvan Yan 	ddi_acc_handle_t handle;
1824*26947304SEvan Yan 	pci_regspec_t *reg;
1825*26947304SEvan Yan 	int length;
1826*26947304SEvan Yan 	int rcount;
1827*26947304SEvan Yan 	int i;
1828*26947304SEvan Yan 	int offset;
1829*26947304SEvan Yan 	uint64_t mem_answer;
1830*26947304SEvan Yan 	uint32_t io_answer;
1831*26947304SEvan Yan 	int count;
1832*26947304SEvan Yan 	uint8_t header_type;
1833*26947304SEvan Yan 	pcicfg_range_t range[PCICFG_RANGE_LEN];
1834*26947304SEvan Yan 	int bus_range[2];
1835*26947304SEvan Yan 
1836*26947304SEvan Yan 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
1837*26947304SEvan Yan 
1838*26947304SEvan Yan 	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
1839*26947304SEvan Yan 
1840*26947304SEvan Yan 	if (entry == NULL) {
1841*26947304SEvan Yan 		DEBUG0("Failed to get entry\n");
1842*26947304SEvan Yan 		return (DDI_WALK_TERMINATE);
1843*26947304SEvan Yan 	}
1844*26947304SEvan Yan 
1845*26947304SEvan Yan 	entry->error = PCICFG_SUCCESS;
1846*26947304SEvan Yan 
1847*26947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
1848*26947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
1849*26947304SEvan Yan 		entry->error = PCICFG_FAILURE;
1850*26947304SEvan Yan 		return (DDI_WALK_TERMINATE);
1851*26947304SEvan Yan 	}
1852*26947304SEvan Yan 
1853*26947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
1854*26947304SEvan Yan 
1855*26947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
1856*26947304SEvan Yan 
1857*26947304SEvan Yan 		bzero((caddr_t)range,
1858*26947304SEvan Yan 		    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
1859*26947304SEvan Yan 
1860*26947304SEvan Yan 		(void) pcicfg_setup_bridge(entry, handle, dip);
1861*26947304SEvan Yan 
1862*26947304SEvan Yan 		range[0].child_hi = range[0].parent_hi |=
1863*26947304SEvan Yan 		    (PCI_REG_REL_M | PCI_ADDR_IO);
1864*26947304SEvan Yan 		range[0].child_lo = range[0].parent_lo =
1865*26947304SEvan Yan 		    entry->io_last;
1866*26947304SEvan Yan 		range[1].child_hi = range[1].parent_hi |=
1867*26947304SEvan Yan 		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
1868*26947304SEvan Yan 		range[1].child_lo = range[1].parent_lo =
1869*26947304SEvan Yan 		    entry->memory_last;
1870*26947304SEvan Yan 
1871*26947304SEvan Yan 		ndi_devi_enter(dip, &count);
1872*26947304SEvan Yan 		ddi_walk_devs(ddi_get_child(dip),
1873*26947304SEvan Yan 		    pcicfg_bridge_assign, (void *)entry);
1874*26947304SEvan Yan 		ndi_devi_exit(dip, count);
1875*26947304SEvan Yan 
1876*26947304SEvan Yan 		(void) pcicfg_update_bridge(entry, handle);
1877*26947304SEvan Yan 
1878*26947304SEvan Yan 		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
1879*26947304SEvan Yan 		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
1880*26947304SEvan Yan 
1881*26947304SEvan Yan 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1882*26947304SEvan Yan 		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
1883*26947304SEvan Yan 			DEBUG0("Failed to set bus-range property");
1884*26947304SEvan Yan 			entry->error = PCICFG_FAILURE;
1885*26947304SEvan Yan 			return (DDI_WALK_TERMINATE);
1886*26947304SEvan Yan 		}
1887*26947304SEvan Yan 
1888*26947304SEvan Yan 		if (entry->io_len > 0) {
1889*26947304SEvan Yan 			range[0].size_lo = entry->io_last - entry->io_base;
1890*26947304SEvan Yan 			if (pcicfg_update_ranges_prop(dip, &range[0])) {
1891*26947304SEvan Yan 				DEBUG0("Failed to update ranges (i/o)\n");
1892*26947304SEvan Yan 				entry->error = PCICFG_FAILURE;
1893*26947304SEvan Yan 				return (DDI_WALK_TERMINATE);
1894*26947304SEvan Yan 			}
1895*26947304SEvan Yan 		}
1896*26947304SEvan Yan 		if (entry->memory_len > 0) {
1897*26947304SEvan Yan 			range[1].size_lo =
1898*26947304SEvan Yan 			    entry->memory_last - entry->memory_base;
1899*26947304SEvan Yan 			if (pcicfg_update_ranges_prop(dip, &range[1])) {
1900*26947304SEvan Yan 				DEBUG0("Failed to update ranges (memory)\n");
1901*26947304SEvan Yan 				entry->error = PCICFG_FAILURE;
1902*26947304SEvan Yan 				return (DDI_WALK_TERMINATE);
1903*26947304SEvan Yan 			}
1904*26947304SEvan Yan 		}
1905*26947304SEvan Yan 
1906*26947304SEvan Yan 		(void) pcicfg_device_on(handle);
1907*26947304SEvan Yan 
1908*26947304SEvan Yan 		PCICFG_DUMP_BRIDGE_CONFIG(handle);
1909*26947304SEvan Yan 
1910*26947304SEvan Yan 		return (DDI_WALK_PRUNECHILD);
1911*26947304SEvan Yan 	}
1912*26947304SEvan Yan 
1913*26947304SEvan Yan 	/*
1914*26947304SEvan Yan 	 * If there is an interrupt pin set program
1915*26947304SEvan Yan 	 * interrupt line with default values.
1916*26947304SEvan Yan 	 */
1917*26947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
1918*26947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
1919*26947304SEvan Yan 	}
1920*26947304SEvan Yan 
1921*26947304SEvan Yan 	/*
1922*26947304SEvan Yan 	 * A single device (under a bridge).
1923*26947304SEvan Yan 	 * For each "reg" property with a length, allocate memory
1924*26947304SEvan Yan 	 * and program the base registers.
1925*26947304SEvan Yan 	 */
1926*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
1927*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
1928*26947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
1929*26947304SEvan Yan 		DEBUG0("Failed to read reg property\n");
1930*26947304SEvan Yan 		entry->error = PCICFG_FAILURE;
1931*26947304SEvan Yan 		return (DDI_WALK_TERMINATE);
1932*26947304SEvan Yan 	}
1933*26947304SEvan Yan 
1934*26947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
1935*26947304SEvan Yan 	offset = PCI_CONF_BASE0;
1936*26947304SEvan Yan 	for (i = 0; i < rcount; i++) {
1937*26947304SEvan Yan 		if ((reg[i].pci_size_low != 0)||
1938*26947304SEvan Yan 		    (reg[i].pci_size_hi != 0)) {
1939*26947304SEvan Yan 
1940*26947304SEvan Yan 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
1941*26947304SEvan Yan 
1942*26947304SEvan Yan 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
1943*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
1944*26947304SEvan Yan 
1945*26947304SEvan Yan 				(void) pcicfg_get_mem(entry,
1946*26947304SEvan Yan 				    reg[i].pci_size_low, &mem_answer);
1947*26947304SEvan Yan 				pci_config_put64(handle, offset, mem_answer);
1948*26947304SEvan Yan 				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
1949*26947304SEvan Yan 				    offset,
1950*26947304SEvan Yan 				    pci_config_get32(handle, offset));
1951*26947304SEvan Yan 				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
1952*26947304SEvan Yan 				    offset + 4,
1953*26947304SEvan Yan 				    pci_config_get32(handle, offset + 4));
1954*26947304SEvan Yan 
1955*26947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer);
1956*26947304SEvan Yan 				reg[i].pci_phys_mid  =
1957*26947304SEvan Yan 				    PCICFG_LOADDR(mem_answer);
1958*26947304SEvan Yan 
1959*26947304SEvan Yan 				break;
1960*26947304SEvan Yan 
1961*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
1962*26947304SEvan Yan 				/* allocate memory space from the allocator */
1963*26947304SEvan Yan 
1964*26947304SEvan Yan 				(void) pcicfg_get_mem(entry,
1965*26947304SEvan Yan 				    reg[i].pci_size_low, &mem_answer);
1966*26947304SEvan Yan 				pci_config_put32(handle,
1967*26947304SEvan Yan 				    offset, (uint32_t)mem_answer);
1968*26947304SEvan Yan 
1969*26947304SEvan Yan 				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
1970*26947304SEvan Yan 				    offset,
1971*26947304SEvan Yan 				    pci_config_get32(handle, offset));
1972*26947304SEvan Yan 
1973*26947304SEvan Yan 				reg[i].pci_phys_low = (uint32_t)mem_answer;
1974*26947304SEvan Yan 
1975*26947304SEvan Yan 				break;
1976*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
1977*26947304SEvan Yan 				/* allocate I/O space from the allocator */
1978*26947304SEvan Yan 
1979*26947304SEvan Yan 				(void) pcicfg_get_io(entry,
1980*26947304SEvan Yan 				    reg[i].pci_size_low, &io_answer);
1981*26947304SEvan Yan 				pci_config_put32(handle, offset, io_answer);
1982*26947304SEvan Yan 
1983*26947304SEvan Yan 				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
1984*26947304SEvan Yan 				    offset,
1985*26947304SEvan Yan 				    pci_config_get32(handle, offset));
1986*26947304SEvan Yan 
1987*26947304SEvan Yan 				reg[i].pci_phys_low = io_answer;
1988*26947304SEvan Yan 
1989*26947304SEvan Yan 				break;
1990*26947304SEvan Yan 			default:
1991*26947304SEvan Yan 				DEBUG0("Unknown register type\n");
1992*26947304SEvan Yan 				kmem_free(reg, length);
1993*26947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
1994*26947304SEvan Yan 				entry->error = PCICFG_FAILURE;
1995*26947304SEvan Yan 				return (DDI_WALK_TERMINATE);
1996*26947304SEvan Yan 			} /* switch */
1997*26947304SEvan Yan 
1998*26947304SEvan Yan 			/*
1999*26947304SEvan Yan 			 * Now that memory locations are assigned,
2000*26947304SEvan Yan 			 * update the assigned address property.
2001*26947304SEvan Yan 			 */
2002*26947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip,
2003*26947304SEvan Yan 			    &reg[i]) != PCICFG_SUCCESS) {
2004*26947304SEvan Yan 				kmem_free(reg, length);
2005*26947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
2006*26947304SEvan Yan 				entry->error = PCICFG_FAILURE;
2007*26947304SEvan Yan 				return (DDI_WALK_TERMINATE);
2008*26947304SEvan Yan 			}
2009*26947304SEvan Yan 		}
2010*26947304SEvan Yan 	}
2011*26947304SEvan Yan 	(void) pcicfg_device_on(handle);
2012*26947304SEvan Yan 
2013*26947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
2014*26947304SEvan Yan 
2015*26947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
2016*26947304SEvan Yan 	/*
2017*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
2018*26947304SEvan Yan 	 */
2019*26947304SEvan Yan 	kmem_free((caddr_t)reg, length);
2020*26947304SEvan Yan 
2021*26947304SEvan Yan 	return (DDI_WALK_CONTINUE);
2022*26947304SEvan Yan }
2023*26947304SEvan Yan 
2024*26947304SEvan Yan static int
2025*26947304SEvan Yan pcicfg_device_assign(dev_info_t *dip)
2026*26947304SEvan Yan {
2027*26947304SEvan Yan 	ddi_acc_handle_t	handle;
2028*26947304SEvan Yan 	pci_regspec_t		*reg;
2029*26947304SEvan Yan 	int			length;
2030*26947304SEvan Yan 	int			rcount;
2031*26947304SEvan Yan 	int			i;
2032*26947304SEvan Yan 	int			offset;
2033*26947304SEvan Yan 	ndi_ra_request_t	request;
2034*26947304SEvan Yan 	uint64_t		answer;
2035*26947304SEvan Yan 	uint64_t		alen;
2036*26947304SEvan Yan 
2037*26947304SEvan Yan 	DEBUG1("%llx now under configuration\n", dip);
2038*26947304SEvan Yan 
2039*26947304SEvan Yan 	/*
2040*26947304SEvan Yan 	 * XXX Failure here should be noted
2041*26947304SEvan Yan 	 */
2042*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2043*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
2044*26947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
2045*26947304SEvan Yan 		DEBUG0("Failed to read reg property\n");
2046*26947304SEvan Yan 		return (PCICFG_FAILURE);
2047*26947304SEvan Yan 	}
2048*26947304SEvan Yan 
2049*26947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
2050*26947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
2051*26947304SEvan Yan 		/*
2052*26947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
2053*26947304SEvan Yan 		 */
2054*26947304SEvan Yan 		kmem_free((caddr_t)reg, length);
2055*26947304SEvan Yan 
2056*26947304SEvan Yan 		return (PCICFG_FAILURE);
2057*26947304SEvan Yan 	}
2058*26947304SEvan Yan 
2059*26947304SEvan Yan 	/*
2060*26947304SEvan Yan 	 * A single device
2061*26947304SEvan Yan 	 *
2062*26947304SEvan Yan 	 * For each "reg" property with a length, allocate memory
2063*26947304SEvan Yan 	 * and program the base registers.
2064*26947304SEvan Yan 	 */
2065*26947304SEvan Yan 
2066*26947304SEvan Yan 	/*
2067*26947304SEvan Yan 	 * If there is an interrupt pin set program
2068*26947304SEvan Yan 	 * interrupt line with default values.
2069*26947304SEvan Yan 	 */
2070*26947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
2071*26947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
2072*26947304SEvan Yan 	}
2073*26947304SEvan Yan 
2074*26947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
2075*26947304SEvan Yan 
2076*26947304SEvan Yan 	request.ra_flags |= NDI_RA_ALIGN_SIZE;
2077*26947304SEvan Yan 	request.ra_boundbase = 0;
2078*26947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
2079*26947304SEvan Yan 
2080*26947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
2081*26947304SEvan Yan 	offset = PCI_CONF_BASE0;
2082*26947304SEvan Yan 	for (i = 0; i < rcount; i++) {
2083*26947304SEvan Yan 		if ((reg[i].pci_size_low != 0)||
2084*26947304SEvan Yan 		    (reg[i].pci_size_hi != 0)) {
2085*26947304SEvan Yan 
2086*26947304SEvan Yan 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
2087*26947304SEvan Yan 			request.ra_len = reg[i].pci_size_low;
2088*26947304SEvan Yan 
2089*26947304SEvan Yan 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
2090*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2091*26947304SEvan Yan 				request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
2092*26947304SEvan Yan 				/* allocate memory space from the allocator */
2093*26947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
2094*26947304SEvan Yan 				    &request, &answer, &alen,
2095*26947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
2096*26947304SEvan Yan 				    != NDI_SUCCESS) {
2097*26947304SEvan Yan 					DEBUG0("Failed to allocate 64b mem\n");
2098*26947304SEvan Yan 					kmem_free(reg, length);
2099*26947304SEvan Yan 					(void) pcicfg_config_teardown(&handle);
2100*26947304SEvan Yan 					return (PCICFG_FAILURE);
2101*26947304SEvan Yan 				}
2102*26947304SEvan Yan 				DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
2103*26947304SEvan Yan 				    PCICFG_HIADDR(answer),
2104*26947304SEvan Yan 				    PCICFG_LOADDR(answer),
2105*26947304SEvan Yan 				    alen);
2106*26947304SEvan Yan 				/* program the low word */
2107*26947304SEvan Yan 				pci_config_put32(handle,
2108*26947304SEvan Yan 				    offset, PCICFG_LOADDR(answer));
2109*26947304SEvan Yan 
2110*26947304SEvan Yan 				/* program the high word with value zero */
2111*26947304SEvan Yan 				pci_config_put32(handle, offset + 4,
2112*26947304SEvan Yan 				    PCICFG_HIADDR(answer));
2113*26947304SEvan Yan 
2114*26947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
2115*26947304SEvan Yan 				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
2116*26947304SEvan Yan 				/*
2117*26947304SEvan Yan 				 * currently support 32b address space
2118*26947304SEvan Yan 				 * assignments only.
2119*26947304SEvan Yan 				 */
2120*26947304SEvan Yan 				reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^
2121*26947304SEvan Yan 				    PCI_ADDR_MEM32;
2122*26947304SEvan Yan 
2123*26947304SEvan Yan 				offset += 8;
2124*26947304SEvan Yan 				break;
2125*26947304SEvan Yan 
2126*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2127*26947304SEvan Yan 				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
2128*26947304SEvan Yan 				/* allocate memory space from the allocator */
2129*26947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
2130*26947304SEvan Yan 				    &request, &answer, &alen,
2131*26947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
2132*26947304SEvan Yan 				    != NDI_SUCCESS) {
2133*26947304SEvan Yan 					DEBUG0("Failed to allocate 32b mem\n");
2134*26947304SEvan Yan 					kmem_free(reg, length);
2135*26947304SEvan Yan 					(void) pcicfg_config_teardown(&handle);
2136*26947304SEvan Yan 					return (PCICFG_FAILURE);
2137*26947304SEvan Yan 				}
2138*26947304SEvan Yan 				DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
2139*26947304SEvan Yan 				    PCICFG_HIADDR(answer),
2140*26947304SEvan Yan 				    PCICFG_LOADDR(answer),
2141*26947304SEvan Yan 				    alen);
2142*26947304SEvan Yan 				/* program the low word */
2143*26947304SEvan Yan 				pci_config_put32(handle,
2144*26947304SEvan Yan 				    offset, PCICFG_LOADDR(answer));
2145*26947304SEvan Yan 
2146*26947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
2147*26947304SEvan Yan 
2148*26947304SEvan Yan 				offset += 4;
2149*26947304SEvan Yan 				break;
2150*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
2151*26947304SEvan Yan 				/* allocate I/O space from the allocator */
2152*26947304SEvan Yan 				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
2153*26947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
2154*26947304SEvan Yan 				    &request, &answer, &alen,
2155*26947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
2156*26947304SEvan Yan 				    != NDI_SUCCESS) {
2157*26947304SEvan Yan 					DEBUG0("Failed to allocate I/O\n");
2158*26947304SEvan Yan 					kmem_free(reg, length);
2159*26947304SEvan Yan 					(void) pcicfg_config_teardown(&handle);
2160*26947304SEvan Yan 					return (PCICFG_FAILURE);
2161*26947304SEvan Yan 				}
2162*26947304SEvan Yan 				DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
2163*26947304SEvan Yan 				    PCICFG_HIADDR(answer),
2164*26947304SEvan Yan 				    PCICFG_LOADDR(answer),
2165*26947304SEvan Yan 				    alen);
2166*26947304SEvan Yan 				pci_config_put32(handle,
2167*26947304SEvan Yan 				    offset, PCICFG_LOADDR(answer));
2168*26947304SEvan Yan 
2169*26947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
2170*26947304SEvan Yan 
2171*26947304SEvan Yan 				offset += 4;
2172*26947304SEvan Yan 				break;
2173*26947304SEvan Yan 			default:
2174*26947304SEvan Yan 				DEBUG0("Unknown register type\n");
2175*26947304SEvan Yan 				kmem_free(reg, length);
2176*26947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
2177*26947304SEvan Yan 				return (PCICFG_FAILURE);
2178*26947304SEvan Yan 			} /* switch */
2179*26947304SEvan Yan 
2180*26947304SEvan Yan 			/*
2181*26947304SEvan Yan 			 * Now that memory locations are assigned,
2182*26947304SEvan Yan 			 * update the assigned address property.
2183*26947304SEvan Yan 			 */
2184*26947304SEvan Yan 
2185*26947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip,
2186*26947304SEvan Yan 			    &reg[i]) != PCICFG_SUCCESS) {
2187*26947304SEvan Yan 				kmem_free(reg, length);
2188*26947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
2189*26947304SEvan Yan 				return (PCICFG_FAILURE);
2190*26947304SEvan Yan 			}
2191*26947304SEvan Yan 		}
2192*26947304SEvan Yan 	}
2193*26947304SEvan Yan 
2194*26947304SEvan Yan 	(void) pcicfg_device_on(handle);
2195*26947304SEvan Yan 	kmem_free(reg, length);
2196*26947304SEvan Yan 
2197*26947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
2198*26947304SEvan Yan 
2199*26947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
2200*26947304SEvan Yan 	return (PCICFG_SUCCESS);
2201*26947304SEvan Yan }
2202*26947304SEvan Yan 
2203*26947304SEvan Yan static int
2204*26947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip)
2205*26947304SEvan Yan {
2206*26947304SEvan Yan 	ddi_acc_handle_t	handle;
2207*26947304SEvan Yan 	pci_regspec_t		*assigned;
2208*26947304SEvan Yan 	int			length;
2209*26947304SEvan Yan 	int			acount;
2210*26947304SEvan Yan 	int			i;
2211*26947304SEvan Yan 	ndi_ra_request_t	request;
2212*26947304SEvan Yan 	uint64_t		answer;
2213*26947304SEvan Yan 	uint64_t		alen;
2214*26947304SEvan Yan 
2215*26947304SEvan Yan 
2216*26947304SEvan Yan 	DEBUG1("%llx now under configuration\n", dip);
2217*26947304SEvan Yan 
2218*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2219*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
2220*26947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
2221*26947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
2222*26947304SEvan Yan 		return (PCICFG_FAILURE);
2223*26947304SEvan Yan 	}
2224*26947304SEvan Yan 
2225*26947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
2226*26947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
2227*26947304SEvan Yan 		/*
2228*26947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
2229*26947304SEvan Yan 		 */
2230*26947304SEvan Yan 		kmem_free((caddr_t)assigned, length);
2231*26947304SEvan Yan 
2232*26947304SEvan Yan 		return (PCICFG_FAILURE);
2233*26947304SEvan Yan 	}
2234*26947304SEvan Yan 
2235*26947304SEvan Yan 	/*
2236*26947304SEvan Yan 	 * For each "assigned-addresses" property entry with a length,
2237*26947304SEvan Yan 	 * call the memory allocation routines to return the
2238*26947304SEvan Yan 	 * resource.
2239*26947304SEvan Yan 	 */
2240*26947304SEvan Yan 	/*
2241*26947304SEvan Yan 	 * If there is an interrupt pin set program
2242*26947304SEvan Yan 	 * interrupt line with default values.
2243*26947304SEvan Yan 	 */
2244*26947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
2245*26947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
2246*26947304SEvan Yan 	}
2247*26947304SEvan Yan 
2248*26947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
2249*26947304SEvan Yan 
2250*26947304SEvan Yan 	request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */
2251*26947304SEvan Yan 	request.ra_boundbase = 0;
2252*26947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
2253*26947304SEvan Yan 
2254*26947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
2255*26947304SEvan Yan 	for (i = 0; i < acount; i++) {
2256*26947304SEvan Yan 		if ((assigned[i].pci_size_low != 0)||
2257*26947304SEvan Yan 		    (assigned[i].pci_size_hi != 0)) {
2258*26947304SEvan Yan 
2259*26947304SEvan Yan 			request.ra_len = assigned[i].pci_size_low;
2260*26947304SEvan Yan 
2261*26947304SEvan Yan 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
2262*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2263*26947304SEvan Yan 				request.ra_addr = (uint64_t)PCICFG_LADDR(
2264*26947304SEvan Yan 				    assigned[i].pci_phys_low,
2265*26947304SEvan Yan 				    assigned[i].pci_phys_mid);
2266*26947304SEvan Yan 
2267*26947304SEvan Yan 				/* allocate memory space from the allocator */
2268*26947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
2269*26947304SEvan Yan 				    &request, &answer, &alen,
2270*26947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
2271*26947304SEvan Yan 				    != NDI_SUCCESS) {
2272*26947304SEvan Yan 					DEBUG0("Failed to allocate 64b mem\n");
2273*26947304SEvan Yan 					kmem_free(assigned, length);
2274*26947304SEvan Yan 					return (PCICFG_FAILURE);
2275*26947304SEvan Yan 				}
2276*26947304SEvan Yan 
2277*26947304SEvan Yan 				break;
2278*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2279*26947304SEvan Yan 				request.ra_addr = (uint64_t)
2280*26947304SEvan Yan 				    assigned[i].pci_phys_low;
2281*26947304SEvan Yan 
2282*26947304SEvan Yan 				/* allocate memory space from the allocator */
2283*26947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
2284*26947304SEvan Yan 				    &request, &answer, &alen,
2285*26947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
2286*26947304SEvan Yan 				    != NDI_SUCCESS) {
2287*26947304SEvan Yan 					DEBUG0("Failed to allocate 32b mem\n");
2288*26947304SEvan Yan 					kmem_free(assigned, length);
2289*26947304SEvan Yan 					return (PCICFG_FAILURE);
2290*26947304SEvan Yan 				}
2291*26947304SEvan Yan 
2292*26947304SEvan Yan 				break;
2293*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
2294*26947304SEvan Yan 				request.ra_addr = (uint64_t)
2295*26947304SEvan Yan 				    assigned[i].pci_phys_low;
2296*26947304SEvan Yan 
2297*26947304SEvan Yan 				/* allocate I/O space from the allocator */
2298*26947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
2299*26947304SEvan Yan 				    &request, &answer, &alen,
2300*26947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
2301*26947304SEvan Yan 				    != NDI_SUCCESS) {
2302*26947304SEvan Yan 					DEBUG0("Failed to allocate I/O\n");
2303*26947304SEvan Yan 					kmem_free(assigned, length);
2304*26947304SEvan Yan 					return (PCICFG_FAILURE);
2305*26947304SEvan Yan 				}
2306*26947304SEvan Yan 
2307*26947304SEvan Yan 				break;
2308*26947304SEvan Yan 			default:
2309*26947304SEvan Yan 				DEBUG0("Unknown register type\n");
2310*26947304SEvan Yan 				kmem_free(assigned, length);
2311*26947304SEvan Yan 				return (PCICFG_FAILURE);
2312*26947304SEvan Yan 			} /* switch */
2313*26947304SEvan Yan 		}
2314*26947304SEvan Yan 	}
2315*26947304SEvan Yan 
2316*26947304SEvan Yan 	(void) pcicfg_device_on(handle);
2317*26947304SEvan Yan 	kmem_free(assigned, length);
2318*26947304SEvan Yan 
2319*26947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
2320*26947304SEvan Yan 
2321*26947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
2322*26947304SEvan Yan 	return (PCICFG_SUCCESS);
2323*26947304SEvan Yan }
2324*26947304SEvan Yan 
2325*26947304SEvan Yan /*
2326*26947304SEvan Yan  * The "dip" passed to this routine is assumed to be
2327*26947304SEvan Yan  * the device at the Hotplug Connection (CN). Currently it is
2328*26947304SEvan Yan  * assumed to be a bridge.
2329*26947304SEvan Yan  */
2330*26947304SEvan Yan static int
2331*26947304SEvan Yan pcicfg_allocate_chunk(dev_info_t *dip)
2332*26947304SEvan Yan {
2333*26947304SEvan Yan 	pcicfg_phdl_t		*phdl;
2334*26947304SEvan Yan 	ndi_ra_request_t	*mem_request;
2335*26947304SEvan Yan 	ndi_ra_request_t	*io_request;
2336*26947304SEvan Yan 	uint64_t		mem_answer;
2337*26947304SEvan Yan 	uint64_t		io_answer;
2338*26947304SEvan Yan 	int			count;
2339*26947304SEvan Yan 	uint64_t		alen;
2340*26947304SEvan Yan 
2341*26947304SEvan Yan 	/*
2342*26947304SEvan Yan 	 * This should not find an existing entry - so
2343*26947304SEvan Yan 	 * it will create a new one.
2344*26947304SEvan Yan 	 */
2345*26947304SEvan Yan 	phdl = pcicfg_find_phdl(dip);
2346*26947304SEvan Yan 	ASSERT(phdl);
2347*26947304SEvan Yan 
2348*26947304SEvan Yan 	mem_request = &phdl->mem_req;
2349*26947304SEvan Yan 	io_request  = &phdl->io_req;
2350*26947304SEvan Yan 
2351*26947304SEvan Yan 	/*
2352*26947304SEvan Yan 	 * From this point in the tree - walk the devices,
2353*26947304SEvan Yan 	 * The function passed in will read and "sum" up
2354*26947304SEvan Yan 	 * the memory and I/O requirements and put them in
2355*26947304SEvan Yan 	 * structure "phdl".
2356*26947304SEvan Yan 	 */
2357*26947304SEvan Yan 	ndi_devi_enter(ddi_get_parent(dip), &count);
2358*26947304SEvan Yan 	ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl);
2359*26947304SEvan Yan 	ndi_devi_exit(ddi_get_parent(dip), count);
2360*26947304SEvan Yan 
2361*26947304SEvan Yan 	if (phdl->error != PCICFG_SUCCESS) {
2362*26947304SEvan Yan 		DEBUG0("Failure summing resources\n");
2363*26947304SEvan Yan 		return (phdl->error);
2364*26947304SEvan Yan 	}
2365*26947304SEvan Yan 
2366*26947304SEvan Yan 	/*
2367*26947304SEvan Yan 	 * Call into the memory allocator with the request.
2368*26947304SEvan Yan 	 * Record the addresses returned in the phdl
2369*26947304SEvan Yan 	 */
2370*26947304SEvan Yan 	DEBUG1("Connector requires [0x%x] bytes of memory space\n",
2371*26947304SEvan Yan 	    mem_request->ra_len);
2372*26947304SEvan Yan 	DEBUG1("Connector requires [0x%x] bytes of I/O space\n",
2373*26947304SEvan Yan 	    io_request->ra_len);
2374*26947304SEvan Yan 
2375*26947304SEvan Yan 	mem_request->ra_align_mask =
2376*26947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
2377*26947304SEvan Yan 	io_request->ra_align_mask =
2378*26947304SEvan Yan 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
2379*26947304SEvan Yan 	io_request->ra_boundbase = 0;
2380*26947304SEvan Yan 	io_request->ra_boundlen = PCICFG_4GIG_LIMIT;
2381*26947304SEvan Yan 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
2382*26947304SEvan Yan 
2383*26947304SEvan Yan 	mem_request->ra_len =
2384*26947304SEvan Yan 	    PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
2385*26947304SEvan Yan 
2386*26947304SEvan Yan 	io_request->ra_len =
2387*26947304SEvan Yan 	    PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
2388*26947304SEvan Yan 
2389*26947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(dip),
2390*26947304SEvan Yan 	    mem_request, &mem_answer, &alen,
2391*26947304SEvan Yan 	    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
2392*26947304SEvan Yan 		DEBUG0("Failed to allocate memory\n");
2393*26947304SEvan Yan 		return (PCICFG_FAILURE);
2394*26947304SEvan Yan 	}
2395*26947304SEvan Yan 
2396*26947304SEvan Yan 	phdl->memory_base = phdl->memory_last = mem_answer;
2397*26947304SEvan Yan 	phdl->memory_len  = alen;
2398*26947304SEvan Yan 
2399*26947304SEvan Yan 	phdl->mem_hole.start = phdl->memory_base;
2400*26947304SEvan Yan 	phdl->mem_hole.len = phdl->memory_len;
2401*26947304SEvan Yan 	phdl->mem_hole.next = (hole_t *)NULL;
2402*26947304SEvan Yan 
2403*26947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer,
2404*26947304SEvan Yan 	    &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
2405*26947304SEvan Yan 
2406*26947304SEvan Yan 		DEBUG0("Failed to allocate I/O space\n");
2407*26947304SEvan Yan 		(void) ndi_ra_free(ddi_get_parent(dip), mem_answer,
2408*26947304SEvan Yan 		    alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
2409*26947304SEvan Yan 		phdl->memory_len = phdl->io_len = 0;
2410*26947304SEvan Yan 		return (PCICFG_FAILURE);
2411*26947304SEvan Yan 	}
2412*26947304SEvan Yan 
2413*26947304SEvan Yan 	phdl->io_base = phdl->io_last = (uint32_t)io_answer;
2414*26947304SEvan Yan 	phdl->io_len  = (uint32_t)alen;
2415*26947304SEvan Yan 
2416*26947304SEvan Yan 	phdl->io_hole.start = phdl->io_base;
2417*26947304SEvan Yan 	phdl->io_hole.len = phdl->io_len;
2418*26947304SEvan Yan 	phdl->io_hole.next = (hole_t *)NULL;
2419*26947304SEvan Yan 
2420*26947304SEvan Yan 	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
2421*26947304SEvan Yan 	    phdl->memory_base, phdl->memory_len);
2422*26947304SEvan Yan 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
2423*26947304SEvan Yan 	    phdl->io_base, phdl->io_len);
2424*26947304SEvan Yan 
2425*26947304SEvan Yan 	return (PCICFG_SUCCESS);
2426*26947304SEvan Yan }
2427*26947304SEvan Yan 
2428*26947304SEvan Yan #ifdef	DEBUG
2429*26947304SEvan Yan /*
2430*26947304SEvan Yan  * This function is useful in debug mode, where we can measure how
2431*26947304SEvan Yan  * much memory was wasted/unallocated in bridge device's domain.
2432*26947304SEvan Yan  */
2433*26947304SEvan Yan static uint64_t
2434*26947304SEvan Yan pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
2435*26947304SEvan Yan {
2436*26947304SEvan Yan 	uint64_t len = 0;
2437*26947304SEvan Yan 	uint32_t count = 0;
2438*26947304SEvan Yan 
2439*26947304SEvan Yan 	do {
2440*26947304SEvan Yan 		len += hole->len;
2441*26947304SEvan Yan 		hole = hole->next;
2442*26947304SEvan Yan 		count++;
2443*26947304SEvan Yan 	} while (hole);
2444*26947304SEvan Yan 	*hole_count = count;
2445*26947304SEvan Yan 	return (len);
2446*26947304SEvan Yan }
2447*26947304SEvan Yan #endif
2448*26947304SEvan Yan 
2449*26947304SEvan Yan /*
2450*26947304SEvan Yan  * This function frees data structures that hold the hole information
2451*26947304SEvan Yan  * which are allocated in pcicfg_alloc_hole(). This is not freeing
2452*26947304SEvan Yan  * any memory allocated through NDI calls.
2453*26947304SEvan Yan  */
2454*26947304SEvan Yan static void
2455*26947304SEvan Yan pcicfg_free_hole(hole_t *addr_hole)
2456*26947304SEvan Yan {
2457*26947304SEvan Yan 	hole_t *nhole, *hole = addr_hole->next;
2458*26947304SEvan Yan 
2459*26947304SEvan Yan 	while (hole) {
2460*26947304SEvan Yan 		nhole = hole->next;
2461*26947304SEvan Yan 		kmem_free(hole, sizeof (hole_t));
2462*26947304SEvan Yan 		hole = nhole;
2463*26947304SEvan Yan 	}
2464*26947304SEvan Yan }
2465*26947304SEvan Yan 
2466*26947304SEvan Yan static uint64_t
2467*26947304SEvan Yan pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
2468*26947304SEvan Yan {
2469*26947304SEvan Yan 	uint64_t actual_hole_start, ostart, olen;
2470*26947304SEvan Yan 	hole_t	*hole = addr_hole, *thole, *nhole;
2471*26947304SEvan Yan 
2472*26947304SEvan Yan 	do {
2473*26947304SEvan Yan 		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
2474*26947304SEvan Yan 		if (((actual_hole_start - hole->start) + length) <= hole->len) {
2475*26947304SEvan Yan 			DEBUG3("hole found. start %llx, len %llx, req=%x\n",
2476*26947304SEvan Yan 			    hole->start, hole->len, length);
2477*26947304SEvan Yan 			ostart = hole->start;
2478*26947304SEvan Yan 			olen = hole->len;
2479*26947304SEvan Yan 			/* current hole parameters adjust */
2480*26947304SEvan Yan 			if ((actual_hole_start - hole->start) == 0) {
2481*26947304SEvan Yan 				hole->start += length;
2482*26947304SEvan Yan 				hole->len -= length;
2483*26947304SEvan Yan 				if (hole->start > *alast)
2484*26947304SEvan Yan 					*alast = hole->start;
2485*26947304SEvan Yan 			} else {
2486*26947304SEvan Yan 				hole->len = actual_hole_start - hole->start;
2487*26947304SEvan Yan 				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
2488*26947304SEvan Yan 				    KM_SLEEP);
2489*26947304SEvan Yan 				nhole->start = actual_hole_start + length;
2490*26947304SEvan Yan 				nhole->len = (ostart + olen) - nhole->start;
2491*26947304SEvan Yan 				nhole->next = NULL;
2492*26947304SEvan Yan 				thole = hole->next;
2493*26947304SEvan Yan 				hole->next = nhole;
2494*26947304SEvan Yan 				nhole->next = thole;
2495*26947304SEvan Yan 				if (nhole->start > *alast)
2496*26947304SEvan Yan 					*alast = nhole->start;
2497*26947304SEvan Yan 				DEBUG2("put new hole to %llx, %llx\n",
2498*26947304SEvan Yan 				    nhole->start, nhole->len);
2499*26947304SEvan Yan 			}
2500*26947304SEvan Yan 			DEBUG2("adjust current hole to %llx, %llx\n",
2501*26947304SEvan Yan 			    hole->start, hole->len);
2502*26947304SEvan Yan 			break;
2503*26947304SEvan Yan 		}
2504*26947304SEvan Yan 		actual_hole_start = 0;
2505*26947304SEvan Yan 		hole = hole->next;
2506*26947304SEvan Yan 	} while (hole);
2507*26947304SEvan Yan 
2508*26947304SEvan Yan 	DEBUG1("return hole at %llx\n", actual_hole_start);
2509*26947304SEvan Yan 	return (actual_hole_start);
2510*26947304SEvan Yan }
2511*26947304SEvan Yan 
2512*26947304SEvan Yan static void
2513*26947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry,
2514*26947304SEvan Yan 	uint32_t length, uint64_t *ans)
2515*26947304SEvan Yan {
2516*26947304SEvan Yan 	uint64_t new_mem;
2517*26947304SEvan Yan 
2518*26947304SEvan Yan 	/* See if there is a hole, that can hold this request. */
2519*26947304SEvan Yan 	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
2520*26947304SEvan Yan 	    length);
2521*26947304SEvan Yan 	if (new_mem) {	/* if non-zero, found a hole. */
2522*26947304SEvan Yan 		if (ans != NULL)
2523*26947304SEvan Yan 			*ans = new_mem;
2524*26947304SEvan Yan 	} else
2525*26947304SEvan Yan 		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
2526*26947304SEvan Yan 		    length, ddi_get_name(entry->dip));
2527*26947304SEvan Yan }
2528*26947304SEvan Yan 
2529*26947304SEvan Yan static void
2530*26947304SEvan Yan pcicfg_get_io(pcicfg_phdl_t *entry,
2531*26947304SEvan Yan 	uint32_t length, uint32_t *ans)
2532*26947304SEvan Yan {
2533*26947304SEvan Yan 	uint32_t new_io;
2534*26947304SEvan Yan 	uint64_t io_last;
2535*26947304SEvan Yan 
2536*26947304SEvan Yan 	/*
2537*26947304SEvan Yan 	 * See if there is a hole, that can hold this request.
2538*26947304SEvan Yan 	 * Pass 64 bit parameters and then truncate to 32 bit.
2539*26947304SEvan Yan 	 */
2540*26947304SEvan Yan 	io_last = entry->io_last;
2541*26947304SEvan Yan 	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
2542*26947304SEvan Yan 	if (new_io) {	/* if non-zero, found a hole. */
2543*26947304SEvan Yan 		entry->io_last = (uint32_t)io_last;
2544*26947304SEvan Yan 		if (ans != NULL)
2545*26947304SEvan Yan 			*ans = new_io;
2546*26947304SEvan Yan 	} else
2547*26947304SEvan Yan 		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
2548*26947304SEvan Yan 		    length, ddi_get_name(entry->dip));
2549*26947304SEvan Yan }
2550*26947304SEvan Yan 
2551*26947304SEvan Yan static int
2552*26947304SEvan Yan pcicfg_sum_resources(dev_info_t *dip, void *hdl)
2553*26947304SEvan Yan {
2554*26947304SEvan Yan 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
2555*26947304SEvan Yan 	pci_regspec_t *pci_rp;
2556*26947304SEvan Yan 	int length;
2557*26947304SEvan Yan 	int rcount;
2558*26947304SEvan Yan 	int i;
2559*26947304SEvan Yan 	ndi_ra_request_t *mem_request;
2560*26947304SEvan Yan 	ndi_ra_request_t *io_request;
2561*26947304SEvan Yan 	uint8_t header_type;
2562*26947304SEvan Yan 	ddi_acc_handle_t handle;
2563*26947304SEvan Yan 
2564*26947304SEvan Yan 	entry->error = PCICFG_SUCCESS;
2565*26947304SEvan Yan 
2566*26947304SEvan Yan 	mem_request = &entry->mem_req;
2567*26947304SEvan Yan 	io_request =  &entry->io_req;
2568*26947304SEvan Yan 
2569*26947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
2570*26947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
2571*26947304SEvan Yan 		entry->error = PCICFG_FAILURE;
2572*26947304SEvan Yan 		return (DDI_WALK_TERMINATE);
2573*26947304SEvan Yan 	}
2574*26947304SEvan Yan 
2575*26947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
2576*26947304SEvan Yan 
2577*26947304SEvan Yan 	/*
2578*26947304SEvan Yan 	 * If its a bridge - just record the highest bus seen
2579*26947304SEvan Yan 	 */
2580*26947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
2581*26947304SEvan Yan 
2582*26947304SEvan Yan 		if (entry->highest_bus < pci_config_get8(handle,
2583*26947304SEvan Yan 		    PCI_BCNF_SECBUS)) {
2584*26947304SEvan Yan 			entry->highest_bus =
2585*26947304SEvan Yan 			    pci_config_get8(handle, PCI_BCNF_SECBUS);
2586*26947304SEvan Yan 		}
2587*26947304SEvan Yan 
2588*26947304SEvan Yan 		(void) pcicfg_config_teardown(&handle);
2589*26947304SEvan Yan 		entry->error = PCICFG_FAILURE;
2590*26947304SEvan Yan 		return (DDI_WALK_CONTINUE);
2591*26947304SEvan Yan 	} else {
2592*26947304SEvan Yan 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2593*26947304SEvan Yan 		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp,
2594*26947304SEvan Yan 		    &length) != DDI_PROP_SUCCESS) {
2595*26947304SEvan Yan 			/*
2596*26947304SEvan Yan 			 * If one node in (the subtree of nodes)
2597*26947304SEvan Yan 			 * does'nt have a "reg" property fail the
2598*26947304SEvan Yan 			 * allocation.
2599*26947304SEvan Yan 			 */
2600*26947304SEvan Yan 			entry->memory_len = 0;
2601*26947304SEvan Yan 			entry->io_len = 0;
2602*26947304SEvan Yan 			entry->error = PCICFG_FAILURE;
2603*26947304SEvan Yan 			return (DDI_WALK_TERMINATE);
2604*26947304SEvan Yan 		}
2605*26947304SEvan Yan 		/*
2606*26947304SEvan Yan 		 * For each "reg" property with a length, add that to the
2607*26947304SEvan Yan 		 * total memory (or I/O) to allocate.
2608*26947304SEvan Yan 		 */
2609*26947304SEvan Yan 		rcount = length / sizeof (pci_regspec_t);
2610*26947304SEvan Yan 
2611*26947304SEvan Yan 		for (i = 0; i < rcount; i++) {
2612*26947304SEvan Yan 
2613*26947304SEvan Yan 			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
2614*26947304SEvan Yan 
2615*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2616*26947304SEvan Yan 				mem_request->ra_len =
2617*26947304SEvan Yan 				    pci_rp[i].pci_size_low +
2618*26947304SEvan Yan 				    PCICFG_ROUND_UP(mem_request->ra_len,
2619*26947304SEvan Yan 				    pci_rp[i].pci_size_low);
2620*26947304SEvan Yan 				DEBUG1("ADDING 32 --->0x%x\n",
2621*26947304SEvan Yan 				    pci_rp[i].pci_size_low);
2622*26947304SEvan Yan 
2623*26947304SEvan Yan 			break;
2624*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2625*26947304SEvan Yan 				mem_request->ra_len =
2626*26947304SEvan Yan 				    pci_rp[i].pci_size_low +
2627*26947304SEvan Yan 				    PCICFG_ROUND_UP(mem_request->ra_len,
2628*26947304SEvan Yan 				    pci_rp[i].pci_size_low);
2629*26947304SEvan Yan 				DEBUG1("ADDING 64 --->0x%x\n",
2630*26947304SEvan Yan 				    pci_rp[i].pci_size_low);
2631*26947304SEvan Yan 
2632*26947304SEvan Yan 			break;
2633*26947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
2634*26947304SEvan Yan 				io_request->ra_len =
2635*26947304SEvan Yan 				    pci_rp[i].pci_size_low +
2636*26947304SEvan Yan 				    PCICFG_ROUND_UP(io_request->ra_len,
2637*26947304SEvan Yan 				    pci_rp[i].pci_size_low);
2638*26947304SEvan Yan 				DEBUG1("ADDING I/O --->0x%x\n",
2639*26947304SEvan Yan 				    pci_rp[i].pci_size_low);
2640*26947304SEvan Yan 			break;
2641*26947304SEvan Yan 			default:
2642*26947304SEvan Yan 			    /* Config space register - not included */
2643*26947304SEvan Yan 			break;
2644*26947304SEvan Yan 			}
2645*26947304SEvan Yan 		}
2646*26947304SEvan Yan 
2647*26947304SEvan Yan 		/*
2648*26947304SEvan Yan 		 * free the memory allocated by ddi_getlongprop
2649*26947304SEvan Yan 		 */
2650*26947304SEvan Yan 		kmem_free(pci_rp, length);
2651*26947304SEvan Yan 
2652*26947304SEvan Yan 		/*
2653*26947304SEvan Yan 		 * continue the walk to the next sibling to sum memory
2654*26947304SEvan Yan 		 */
2655*26947304SEvan Yan 
2656*26947304SEvan Yan 		(void) pcicfg_config_teardown(&handle);
2657*26947304SEvan Yan 
2658*26947304SEvan Yan 		return (DDI_WALK_CONTINUE);
2659*26947304SEvan Yan 	}
2660*26947304SEvan Yan }
2661*26947304SEvan Yan 
2662*26947304SEvan Yan static int
2663*26947304SEvan Yan pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
2664*26947304SEvan Yan {
2665*26947304SEvan Yan 	pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl;
2666*26947304SEvan Yan 	pci_regspec_t *pci_ap;
2667*26947304SEvan Yan 	pcicfg_range_t *ranges;
2668*26947304SEvan Yan 	int length;
2669*26947304SEvan Yan 	int rcount;
2670*26947304SEvan Yan 	int i;
2671*26947304SEvan Yan 
2672*26947304SEvan Yan 	entry_p->error = PCICFG_SUCCESS;
2673*26947304SEvan Yan 
2674*26947304SEvan Yan 	if (dip == entry_p->dip) {
2675*26947304SEvan Yan 		DEBUG0("Don't include parent bridge node\n");
2676*26947304SEvan Yan 		return (DDI_WALK_CONTINUE);
2677*26947304SEvan Yan 	}
2678*26947304SEvan Yan 
2679*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2680*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "ranges",
2681*26947304SEvan Yan 	    (caddr_t)&ranges,  &length) != DDI_PROP_SUCCESS) {
2682*26947304SEvan Yan 		DEBUG0("Node doesn't have ranges\n");
2683*26947304SEvan Yan 		goto ap;
2684*26947304SEvan Yan 	}
2685*26947304SEvan Yan 
2686*26947304SEvan Yan 	rcount = length / sizeof (pcicfg_range_t);
2687*26947304SEvan Yan 
2688*26947304SEvan Yan 	for (i = 0; i < rcount; i++) {
2689*26947304SEvan Yan 		uint64_t base;
2690*26947304SEvan Yan 		uint64_t mid = ranges[i].child_mid;
2691*26947304SEvan Yan 		uint64_t lo = ranges[i].child_lo;
2692*26947304SEvan Yan 		uint64_t size = ranges[i].size_lo;
2693*26947304SEvan Yan 
2694*26947304SEvan Yan 		switch (PCI_REG_ADDR_G(ranges[i].child_hi)) {
2695*26947304SEvan Yan 
2696*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2697*26947304SEvan Yan 			base = entry_p->memory_base;
2698*26947304SEvan Yan 			entry_p->memory_base = MAX(base, lo + size);
2699*26947304SEvan Yan 			break;
2700*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2701*26947304SEvan Yan 			base = entry_p->memory_base;
2702*26947304SEvan Yan 			entry_p->memory_base = MAX(base,
2703*26947304SEvan Yan 			    PCICFG_LADDR(lo, mid) + size);
2704*26947304SEvan Yan 			break;
2705*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
2706*26947304SEvan Yan 			base = entry_p->io_base;
2707*26947304SEvan Yan 			entry_p->io_base = MAX(base, lo + size);
2708*26947304SEvan Yan 			break;
2709*26947304SEvan Yan 		}
2710*26947304SEvan Yan 	}
2711*26947304SEvan Yan 
2712*26947304SEvan Yan 	kmem_free(ranges, length);
2713*26947304SEvan Yan 	return (DDI_WALK_CONTINUE);
2714*26947304SEvan Yan 
2715*26947304SEvan Yan ap:	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2716*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses",
2717*26947304SEvan Yan 	    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
2718*26947304SEvan Yan 		DEBUG0("Node doesn't have assigned-addresses\n");
2719*26947304SEvan Yan 		return (DDI_WALK_CONTINUE);
2720*26947304SEvan Yan 	}
2721*26947304SEvan Yan 
2722*26947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
2723*26947304SEvan Yan 
2724*26947304SEvan Yan 	for (i = 0; i < rcount; i++) {
2725*26947304SEvan Yan 
2726*26947304SEvan Yan 		switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
2727*26947304SEvan Yan 
2728*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2729*26947304SEvan Yan 			if ((pci_ap[i].pci_phys_low +
2730*26947304SEvan Yan 			    pci_ap[i].pci_size_low) >
2731*26947304SEvan Yan 			    entry_p->memory_base) {
2732*26947304SEvan Yan 				entry_p->memory_base =
2733*26947304SEvan Yan 				    pci_ap[i].pci_phys_low +
2734*26947304SEvan Yan 				    pci_ap[i].pci_size_low;
2735*26947304SEvan Yan 			}
2736*26947304SEvan Yan 		break;
2737*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2738*26947304SEvan Yan 			if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
2739*26947304SEvan Yan 			    pci_ap[i].pci_phys_mid) +
2740*26947304SEvan Yan 			    pci_ap[i].pci_size_low) >
2741*26947304SEvan Yan 			    entry_p->memory_base) {
2742*26947304SEvan Yan 				entry_p->memory_base = PCICFG_LADDR(
2743*26947304SEvan Yan 				    pci_ap[i].pci_phys_low,
2744*26947304SEvan Yan 				    pci_ap[i].pci_phys_mid) +
2745*26947304SEvan Yan 				    pci_ap[i].pci_size_low;
2746*26947304SEvan Yan 			}
2747*26947304SEvan Yan 		break;
2748*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
2749*26947304SEvan Yan 			if ((pci_ap[i].pci_phys_low +
2750*26947304SEvan Yan 			    pci_ap[i].pci_size_low) >
2751*26947304SEvan Yan 			    entry_p->io_base) {
2752*26947304SEvan Yan 				entry_p->io_base =
2753*26947304SEvan Yan 				    pci_ap[i].pci_phys_low +
2754*26947304SEvan Yan 				    pci_ap[i].pci_size_low;
2755*26947304SEvan Yan 			}
2756*26947304SEvan Yan 		break;
2757*26947304SEvan Yan 		}
2758*26947304SEvan Yan 	}
2759*26947304SEvan Yan 
2760*26947304SEvan Yan 	/*
2761*26947304SEvan Yan 	 * free the memory allocated by ddi_getlongprop
2762*26947304SEvan Yan 	 */
2763*26947304SEvan Yan 	kmem_free(pci_ap, length);
2764*26947304SEvan Yan 
2765*26947304SEvan Yan 	/*
2766*26947304SEvan Yan 	 * continue the walk to the next sibling to sum memory
2767*26947304SEvan Yan 	 */
2768*26947304SEvan Yan 	return (DDI_WALK_CONTINUE);
2769*26947304SEvan Yan }
2770*26947304SEvan Yan 
2771*26947304SEvan Yan static int
2772*26947304SEvan Yan pcicfg_free_bridge_resources(dev_info_t *dip)
2773*26947304SEvan Yan {
2774*26947304SEvan Yan 	pcicfg_range_t		*ranges;
2775*26947304SEvan Yan 	uint_t			*bus;
2776*26947304SEvan Yan 	int			k;
2777*26947304SEvan Yan 	int			length;
2778*26947304SEvan Yan 	int			i;
2779*26947304SEvan Yan 
2780*26947304SEvan Yan 
2781*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2782*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
2783*26947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
2784*26947304SEvan Yan 		DEBUG0("Failed to read ranges property\n");
2785*26947304SEvan Yan 		if (ddi_get_child(dip)) {
2786*26947304SEvan Yan 			cmn_err(CE_WARN, "No ranges property found for %s",
2787*26947304SEvan Yan 			    ddi_get_name(dip));
2788*26947304SEvan Yan 			/*
2789*26947304SEvan Yan 			 * strictly speaking, we can check for children with
2790*26947304SEvan Yan 			 * assigned-addresses but for now it is better to
2791*26947304SEvan Yan 			 * be conservative and assume that if there are child
2792*26947304SEvan Yan 			 * nodes, then they do consume PCI memory or IO
2793*26947304SEvan Yan 			 * resources, Hence return failure.
2794*26947304SEvan Yan 			 */
2795*26947304SEvan Yan 			return (PCICFG_FAILURE);
2796*26947304SEvan Yan 		}
2797*26947304SEvan Yan 		length = 0;
2798*26947304SEvan Yan 
2799*26947304SEvan Yan 	}
2800*26947304SEvan Yan 
2801*26947304SEvan Yan 	for (i = 0; i < length / sizeof (pcicfg_range_t); i++) {
2802*26947304SEvan Yan 		if (ranges[i].size_lo != 0 ||
2803*26947304SEvan Yan 		    ranges[i].size_hi != 0) {
2804*26947304SEvan Yan 			switch (ranges[i].parent_hi & PCI_REG_ADDR_M) {
2805*26947304SEvan Yan 				case PCI_ADDR_IO:
2806*26947304SEvan Yan 					DEBUG2("Free I/O    "
2807*26947304SEvan Yan 					    "base/length = [0x%x]/[0x%x]\n",
2808*26947304SEvan Yan 					    ranges[i].child_lo,
2809*26947304SEvan Yan 					    ranges[i].size_lo);
2810*26947304SEvan Yan 					if (ndi_ra_free(ddi_get_parent(dip),
2811*26947304SEvan Yan 					    (uint64_t)ranges[i].child_lo,
2812*26947304SEvan Yan 					    (uint64_t)ranges[i].size_lo,
2813*26947304SEvan Yan 					    NDI_RA_TYPE_IO, NDI_RA_PASS)
2814*26947304SEvan Yan 					    != NDI_SUCCESS) {
2815*26947304SEvan Yan 						DEBUG0("Trouble freeing "
2816*26947304SEvan Yan 						    "PCI i/o space\n");
2817*26947304SEvan Yan 						kmem_free(ranges, length);
2818*26947304SEvan Yan 						return (PCICFG_FAILURE);
2819*26947304SEvan Yan 					}
2820*26947304SEvan Yan 				break;
2821*26947304SEvan Yan 				case PCI_ADDR_MEM32:
2822*26947304SEvan Yan 				case PCI_ADDR_MEM64:
2823*26947304SEvan Yan 					DEBUG3("Free Memory base/length = "
2824*26947304SEvan Yan 					    "[0x%x.%x]/[0x%x]\n",
2825*26947304SEvan Yan 					    ranges[i].child_mid,
2826*26947304SEvan Yan 					    ranges[i].child_lo,
2827*26947304SEvan Yan 					    ranges[i].size_lo)
2828*26947304SEvan Yan 					if (ndi_ra_free(ddi_get_parent(dip),
2829*26947304SEvan Yan 					    PCICFG_LADDR(ranges[i].child_lo,
2830*26947304SEvan Yan 					    ranges[i].child_mid),
2831*26947304SEvan Yan 					    (uint64_t)ranges[i].size_lo,
2832*26947304SEvan Yan 					    NDI_RA_TYPE_MEM, NDI_RA_PASS)
2833*26947304SEvan Yan 					    != NDI_SUCCESS) {
2834*26947304SEvan Yan 						DEBUG0("Trouble freeing "
2835*26947304SEvan Yan 						    "PCI memory space\n");
2836*26947304SEvan Yan 						kmem_free(ranges, length);
2837*26947304SEvan Yan 						return (PCICFG_FAILURE);
2838*26947304SEvan Yan 					}
2839*26947304SEvan Yan 				break;
2840*26947304SEvan Yan 				default:
2841*26947304SEvan Yan 					DEBUG0("Unknown memory space\n");
2842*26947304SEvan Yan 				break;
2843*26947304SEvan Yan 			}
2844*26947304SEvan Yan 		}
2845*26947304SEvan Yan 	}
2846*26947304SEvan Yan 
2847*26947304SEvan Yan 	if (length)
2848*26947304SEvan Yan 		kmem_free(ranges, length);
2849*26947304SEvan Yan 
2850*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2851*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
2852*26947304SEvan Yan 	    &k) != DDI_PROP_SUCCESS) {
2853*26947304SEvan Yan 		DEBUG0("Failed to read bus-range property\n");
2854*26947304SEvan Yan 		return (PCICFG_FAILURE);
2855*26947304SEvan Yan 	}
2856*26947304SEvan Yan 
2857*26947304SEvan Yan 	DEBUG2("Need to free bus [%d] range [%d]\n",
2858*26947304SEvan Yan 	    bus[0], bus[1] - bus[0] + 1);
2859*26947304SEvan Yan 
2860*26947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip),
2861*26947304SEvan Yan 	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
2862*26947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
2863*26947304SEvan Yan 		/*EMPTY*/
2864*26947304SEvan Yan 		DEBUG0("Failed to free a bus number\n");
2865*26947304SEvan Yan 	}
2866*26947304SEvan Yan 	/*
2867*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
2868*26947304SEvan Yan 	 */
2869*26947304SEvan Yan 	kmem_free((caddr_t)bus, k);
2870*26947304SEvan Yan 
2871*26947304SEvan Yan 	return (PCICFG_SUCCESS);
2872*26947304SEvan Yan }
2873*26947304SEvan Yan 
2874*26947304SEvan Yan static int
2875*26947304SEvan Yan pcicfg_free_device_resources(dev_info_t *dip, pcicfg_flags_t flags)
2876*26947304SEvan Yan {
2877*26947304SEvan Yan 	pci_regspec_t *assigned;
2878*26947304SEvan Yan 
2879*26947304SEvan Yan 	int length;
2880*26947304SEvan Yan 	int acount;
2881*26947304SEvan Yan 	int i;
2882*26947304SEvan Yan 
2883*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2884*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
2885*26947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
2886*26947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
2887*26947304SEvan Yan 		return (PCICFG_FAILURE);
2888*26947304SEvan Yan 	}
2889*26947304SEvan Yan 
2890*26947304SEvan Yan 	/*
2891*26947304SEvan Yan 	 * For each "assigned-addresses" property entry with a length,
2892*26947304SEvan Yan 	 * call the memory allocation routines to return the
2893*26947304SEvan Yan 	 * resource.
2894*26947304SEvan Yan 	 */
2895*26947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
2896*26947304SEvan Yan 	for (i = 0; i < acount; i++) {
2897*26947304SEvan Yan 		/*
2898*26947304SEvan Yan 		 * Workaround for Devconf (x86) bug to skip extra entries
2899*26947304SEvan Yan 		 * beyond the PCI_CONF_BASE5 offset. But we want to free up
2900*26947304SEvan Yan 		 * any memory for expansion roms if allocated.
2901*26947304SEvan Yan 		 */
2902*26947304SEvan Yan 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) &&
2903*26947304SEvan Yan 		    (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM))
2904*26947304SEvan Yan 			break;
2905*26947304SEvan Yan 
2906*26947304SEvan Yan 		if (pcicfg_free_resource(dip, assigned[i], flags)) {
2907*26947304SEvan Yan 			DEBUG1("pcicfg_free_device_resources - Trouble freeing "
2908*26947304SEvan Yan 			    "%x\n", assigned[i].pci_phys_hi);
2909*26947304SEvan Yan 			/*
2910*26947304SEvan Yan 			 * Don't forget to free up memory from ddi_getlongprop
2911*26947304SEvan Yan 			 */
2912*26947304SEvan Yan 			kmem_free((caddr_t)assigned, length);
2913*26947304SEvan Yan 
2914*26947304SEvan Yan 			return (PCICFG_FAILURE);
2915*26947304SEvan Yan 		}
2916*26947304SEvan Yan 	}
2917*26947304SEvan Yan 	kmem_free(assigned, length);
2918*26947304SEvan Yan 	return (PCICFG_SUCCESS);
2919*26947304SEvan Yan }
2920*26947304SEvan Yan 
2921*26947304SEvan Yan static int
2922*26947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
2923*26947304SEvan Yan {
2924*26947304SEvan Yan 	ddi_acc_handle_t handle;
2925*26947304SEvan Yan 	uint8_t header_type;
2926*26947304SEvan Yan 
2927*26947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
2928*26947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
2929*26947304SEvan Yan 		return (PCICFG_FAILURE);
2930*26947304SEvan Yan 	}
2931*26947304SEvan Yan 
2932*26947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
2933*26947304SEvan Yan 
2934*26947304SEvan Yan 	(void) pci_config_teardown(&handle);
2935*26947304SEvan Yan 
2936*26947304SEvan Yan 	/*
2937*26947304SEvan Yan 	 * A different algorithm is used for bridges and leaf devices.
2938*26947304SEvan Yan 	 */
2939*26947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
2940*26947304SEvan Yan 		/*
2941*26947304SEvan Yan 		 * We only support readonly probing for leaf devices.
2942*26947304SEvan Yan 		 */
2943*26947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
2944*26947304SEvan Yan 			return (PCICFG_FAILURE);
2945*26947304SEvan Yan 
2946*26947304SEvan Yan 		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
2947*26947304SEvan Yan 			DEBUG0("Failed freeing up bridge resources\n");
2948*26947304SEvan Yan 			return (PCICFG_FAILURE);
2949*26947304SEvan Yan 		}
2950*26947304SEvan Yan 	} else {
2951*26947304SEvan Yan 		if (pcicfg_free_device_resources(dip, flags)
2952*26947304SEvan Yan 		    != PCICFG_SUCCESS) {
2953*26947304SEvan Yan 			DEBUG0("Failed freeing up device resources\n");
2954*26947304SEvan Yan 			return (PCICFG_FAILURE);
2955*26947304SEvan Yan 		}
2956*26947304SEvan Yan 	}
2957*26947304SEvan Yan 	return (PCICFG_SUCCESS);
2958*26947304SEvan Yan }
2959*26947304SEvan Yan 
2960*26947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES
2961*26947304SEvan Yan static char *
2962*26947304SEvan Yan pcicfg_get_class_name(uint32_t classcode)
2963*26947304SEvan Yan {
2964*26947304SEvan Yan 	struct pcicfg_name_entry *ptr;
2965*26947304SEvan Yan 
2966*26947304SEvan Yan 	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
2967*26947304SEvan Yan 		if (ptr->class_code == classcode) {
2968*26947304SEvan Yan 			return (ptr->name);
2969*26947304SEvan Yan 		}
2970*26947304SEvan Yan 	}
2971*26947304SEvan Yan 	return (NULL);
2972*26947304SEvan Yan }
2973*26947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */
2974*26947304SEvan Yan 
2975*26947304SEvan Yan static dev_info_t *
2976*26947304SEvan Yan pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
2977*26947304SEvan Yan {
2978*26947304SEvan Yan 	struct pcicfg_find_ctrl ctrl;
2979*26947304SEvan Yan 	int count;
2980*26947304SEvan Yan 
2981*26947304SEvan Yan 	ctrl.device = device;
2982*26947304SEvan Yan 	ctrl.function = function;
2983*26947304SEvan Yan 	ctrl.dip = NULL;
2984*26947304SEvan Yan 
2985*26947304SEvan Yan 	ndi_devi_enter(dip, &count);
2986*26947304SEvan Yan 	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
2987*26947304SEvan Yan 	ndi_devi_exit(dip, count);
2988*26947304SEvan Yan 
2989*26947304SEvan Yan 	return (ctrl.dip);
2990*26947304SEvan Yan }
2991*26947304SEvan Yan 
2992*26947304SEvan Yan static int
2993*26947304SEvan Yan pcicfg_match_dev(dev_info_t *dip, void *hdl)
2994*26947304SEvan Yan {
2995*26947304SEvan Yan 	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
2996*26947304SEvan Yan 	pci_regspec_t *pci_rp;
2997*26947304SEvan Yan 	int length;
2998*26947304SEvan Yan 	int pci_dev;
2999*26947304SEvan Yan 	int pci_func;
3000*26947304SEvan Yan 
3001*26947304SEvan Yan 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
3002*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
3003*26947304SEvan Yan 	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
3004*26947304SEvan Yan 		ctrl->dip = NULL;
3005*26947304SEvan Yan 		return (DDI_WALK_TERMINATE);
3006*26947304SEvan Yan 	}
3007*26947304SEvan Yan 
3008*26947304SEvan Yan 	/* get the PCI device address info */
3009*26947304SEvan Yan 	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
3010*26947304SEvan Yan 	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
3011*26947304SEvan Yan 
3012*26947304SEvan Yan 	/*
3013*26947304SEvan Yan 	 * free the memory allocated by ddi_prop_lookup_int_array
3014*26947304SEvan Yan 	 */
3015*26947304SEvan Yan 	ddi_prop_free(pci_rp);
3016*26947304SEvan Yan 
3017*26947304SEvan Yan 
3018*26947304SEvan Yan 	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
3019*26947304SEvan Yan 		/* found the match for the specified device address */
3020*26947304SEvan Yan 		ctrl->dip = dip;
3021*26947304SEvan Yan 		return (DDI_WALK_TERMINATE);
3022*26947304SEvan Yan 	}
3023*26947304SEvan Yan 
3024*26947304SEvan Yan 	/*
3025*26947304SEvan Yan 	 * continue the walk to the next sibling to look for a match.
3026*26947304SEvan Yan 	 */
3027*26947304SEvan Yan 	return (DDI_WALK_PRUNECHILD);
3028*26947304SEvan Yan }
3029*26947304SEvan Yan 
3030*26947304SEvan Yan static int
3031*26947304SEvan Yan pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
3032*26947304SEvan Yan {
3033*26947304SEvan Yan 	int		alen;
3034*26947304SEvan Yan 	pci_regspec_t	*assigned;
3035*26947304SEvan Yan 	caddr_t		newreg;
3036*26947304SEvan Yan 	uint_t		status;
3037*26947304SEvan Yan 
3038*26947304SEvan Yan 	DEBUG0("pcicfg_update_assigned_prop()\n");
3039*26947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3040*26947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &alen);
3041*26947304SEvan Yan 	switch (status) {
3042*26947304SEvan Yan 		case DDI_PROP_SUCCESS:
3043*26947304SEvan Yan 		break;
3044*26947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
3045*26947304SEvan Yan 			DEBUG0("no memory for assigned-addresses property\n");
3046*26947304SEvan Yan 			return (PCICFG_FAILURE);
3047*26947304SEvan Yan 		default:
3048*26947304SEvan Yan 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3049*26947304SEvan Yan 			    "assigned-addresses", (int *)newone,
3050*26947304SEvan Yan 			    sizeof (*newone)/sizeof (int));
3051*26947304SEvan Yan 
3052*26947304SEvan Yan 			(void) pcicfg_dump_assigned(dip);
3053*26947304SEvan Yan 
3054*26947304SEvan Yan 			return (PCICFG_SUCCESS);
3055*26947304SEvan Yan 	}
3056*26947304SEvan Yan 
3057*26947304SEvan Yan 	/*
3058*26947304SEvan Yan 	 * Allocate memory for the existing
3059*26947304SEvan Yan 	 * assigned-addresses(s) plus one and then
3060*26947304SEvan Yan 	 * build it.
3061*26947304SEvan Yan 	 */
3062*26947304SEvan Yan 
3063*26947304SEvan Yan 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
3064*26947304SEvan Yan 
3065*26947304SEvan Yan 	bcopy(assigned, newreg, alen);
3066*26947304SEvan Yan 	bcopy(newone, newreg + alen, sizeof (*newone));
3067*26947304SEvan Yan 
3068*26947304SEvan Yan 	/*
3069*26947304SEvan Yan 	 * Write out the new "assigned-addresses" spec
3070*26947304SEvan Yan 	 */
3071*26947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3072*26947304SEvan Yan 	    "assigned-addresses", (int *)newreg,
3073*26947304SEvan Yan 	    (alen + sizeof (*newone))/sizeof (int));
3074*26947304SEvan Yan 
3075*26947304SEvan Yan 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
3076*26947304SEvan Yan 
3077*26947304SEvan Yan 	/*
3078*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
3079*26947304SEvan Yan 	 */
3080*26947304SEvan Yan 	kmem_free((caddr_t)assigned, alen);
3081*26947304SEvan Yan 
3082*26947304SEvan Yan 	(void) pcicfg_dump_assigned(dip);
3083*26947304SEvan Yan 
3084*26947304SEvan Yan 	return (PCICFG_SUCCESS);
3085*26947304SEvan Yan }
3086*26947304SEvan Yan static int
3087*26947304SEvan Yan pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition)
3088*26947304SEvan Yan {
3089*26947304SEvan Yan 	int		rlen;
3090*26947304SEvan Yan 	pcicfg_range_t	*ranges;
3091*26947304SEvan Yan 	caddr_t		newreg;
3092*26947304SEvan Yan 	uint_t		status;
3093*26947304SEvan Yan 
3094*26947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
3095*26947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen);
3096*26947304SEvan Yan 
3097*26947304SEvan Yan 
3098*26947304SEvan Yan 	switch (status) {
3099*26947304SEvan Yan 		case DDI_PROP_SUCCESS:
3100*26947304SEvan Yan 		break;
3101*26947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
3102*26947304SEvan Yan 			DEBUG0("ranges present, but unable to get memory\n");
3103*26947304SEvan Yan 			return (PCICFG_FAILURE);
3104*26947304SEvan Yan 		default:
3105*26947304SEvan Yan 			DEBUG0("no ranges property - creating one\n");
3106*26947304SEvan Yan 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
3107*26947304SEvan Yan 			    dip, "ranges", (int *)addition,
3108*26947304SEvan Yan 			    sizeof (pcicfg_range_t)/sizeof (int))
3109*26947304SEvan Yan 			    != DDI_SUCCESS) {
3110*26947304SEvan Yan 				DEBUG0("Did'nt create ranges property\n");
3111*26947304SEvan Yan 				return (PCICFG_FAILURE);
3112*26947304SEvan Yan 			}
3113*26947304SEvan Yan 			return (PCICFG_SUCCESS);
3114*26947304SEvan Yan 	}
3115*26947304SEvan Yan 
3116*26947304SEvan Yan 	/*
3117*26947304SEvan Yan 	 * Allocate memory for the existing reg(s) plus one and then
3118*26947304SEvan Yan 	 * build it.
3119*26947304SEvan Yan 	 */
3120*26947304SEvan Yan 	newreg = kmem_zalloc(rlen + sizeof (pcicfg_range_t), KM_SLEEP);
3121*26947304SEvan Yan 
3122*26947304SEvan Yan 	bcopy(ranges, newreg, rlen);
3123*26947304SEvan Yan 	bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t));
3124*26947304SEvan Yan 
3125*26947304SEvan Yan 	/*
3126*26947304SEvan Yan 	 * Write out the new "ranges" property
3127*26947304SEvan Yan 	 */
3128*26947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
3129*26947304SEvan Yan 	    dip, "ranges", (int *)newreg,
3130*26947304SEvan Yan 	    (rlen + sizeof (pcicfg_range_t))/sizeof (int));
3131*26947304SEvan Yan 
3132*26947304SEvan Yan 	kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t));
3133*26947304SEvan Yan 
3134*26947304SEvan Yan 	kmem_free((caddr_t)ranges, rlen);
3135*26947304SEvan Yan 
3136*26947304SEvan Yan 	return (PCICFG_SUCCESS);
3137*26947304SEvan Yan }
3138*26947304SEvan Yan 
3139*26947304SEvan Yan static int
3140*26947304SEvan Yan pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
3141*26947304SEvan Yan {
3142*26947304SEvan Yan 	int		rlen;
3143*26947304SEvan Yan 	pci_regspec_t	*reg;
3144*26947304SEvan Yan 	caddr_t		newreg;
3145*26947304SEvan Yan 	uint32_t	hiword;
3146*26947304SEvan Yan 	pci_regspec_t	addition;
3147*26947304SEvan Yan 	uint32_t	size;
3148*26947304SEvan Yan 	uint_t		status;
3149*26947304SEvan Yan 
3150*26947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
3151*26947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
3152*26947304SEvan Yan 
3153*26947304SEvan Yan 	switch (status) {
3154*26947304SEvan Yan 		case DDI_PROP_SUCCESS:
3155*26947304SEvan Yan 		break;
3156*26947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
3157*26947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
3158*26947304SEvan Yan 			return (PCICFG_FAILURE);
3159*26947304SEvan Yan 		default:
3160*26947304SEvan Yan 			DEBUG0("no reg property\n");
3161*26947304SEvan Yan 			return (PCICFG_FAILURE);
3162*26947304SEvan Yan 	}
3163*26947304SEvan Yan 
3164*26947304SEvan Yan 	/*
3165*26947304SEvan Yan 	 * Allocate memory for the existing reg(s) plus one and then
3166*26947304SEvan Yan 	 * build it.
3167*26947304SEvan Yan 	 */
3168*26947304SEvan Yan 	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
3169*26947304SEvan Yan 
3170*26947304SEvan Yan 	/*
3171*26947304SEvan Yan 	 * Build the regspec, then add it to the existing one(s)
3172*26947304SEvan Yan 	 */
3173*26947304SEvan Yan 
3174*26947304SEvan Yan 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
3175*26947304SEvan Yan 	    PCI_REG_DEV_G(reg->pci_phys_hi),
3176*26947304SEvan Yan 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
3177*26947304SEvan Yan 
3178*26947304SEvan Yan 	if (reg_offset == PCI_CONF_ROM) {
3179*26947304SEvan Yan 		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
3180*26947304SEvan Yan 		hiword |= PCI_ADDR_MEM32;
3181*26947304SEvan Yan 	} else {
3182*26947304SEvan Yan 		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
3183*26947304SEvan Yan 
3184*26947304SEvan Yan 		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
3185*26947304SEvan Yan 			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
3186*26947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
3187*26947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & regvalue)
3188*26947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
3189*26947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
3190*26947304SEvan Yan 			}
3191*26947304SEvan Yan 		} else {
3192*26947304SEvan Yan 			hiword |= PCI_ADDR_IO;
3193*26947304SEvan Yan 		}
3194*26947304SEvan Yan 	}
3195*26947304SEvan Yan 
3196*26947304SEvan Yan 	addition.pci_phys_hi = hiword;
3197*26947304SEvan Yan 	addition.pci_phys_mid = 0;
3198*26947304SEvan Yan 	addition.pci_phys_low = 0;
3199*26947304SEvan Yan 	addition.pci_size_hi = 0;
3200*26947304SEvan Yan 	addition.pci_size_low = size;
3201*26947304SEvan Yan 
3202*26947304SEvan Yan 	bcopy(reg, newreg, rlen);
3203*26947304SEvan Yan 	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
3204*26947304SEvan Yan 
3205*26947304SEvan Yan 	/*
3206*26947304SEvan Yan 	 * Write out the new "reg" property
3207*26947304SEvan Yan 	 */
3208*26947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
3209*26947304SEvan Yan 	    dip, "reg", (int *)newreg,
3210*26947304SEvan Yan 	    (rlen + sizeof (pci_regspec_t))/sizeof (int));
3211*26947304SEvan Yan 
3212*26947304SEvan Yan 	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
3213*26947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
3214*26947304SEvan Yan 
3215*26947304SEvan Yan 	return (PCICFG_SUCCESS);
3216*26947304SEvan Yan }
3217*26947304SEvan Yan static int
3218*26947304SEvan Yan pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone)
3219*26947304SEvan Yan {
3220*26947304SEvan Yan 	int		alen;
3221*26947304SEvan Yan 	pci_regspec_t	*avail_p;
3222*26947304SEvan Yan 	caddr_t		new_avail;
3223*26947304SEvan Yan 	uint_t		status;
3224*26947304SEvan Yan 
3225*26947304SEvan Yan 	DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n",
3226*26947304SEvan Yan 	    newone->pci_phys_low, newone->pci_size_low);
3227*26947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3228*26947304SEvan Yan 	    "available", (caddr_t)&avail_p, &alen);
3229*26947304SEvan Yan 	switch (status) {
3230*26947304SEvan Yan 		case DDI_PROP_SUCCESS:
3231*26947304SEvan Yan 			break;
3232*26947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
3233*26947304SEvan Yan 			DEBUG0("no memory for available property\n");
3234*26947304SEvan Yan 			return (PCICFG_FAILURE);
3235*26947304SEvan Yan 		default:
3236*26947304SEvan Yan 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3237*26947304SEvan Yan 			    "available", (int *)newone,
3238*26947304SEvan Yan 			    sizeof (*newone)/sizeof (int));
3239*26947304SEvan Yan 
3240*26947304SEvan Yan 			return (PCICFG_SUCCESS);
3241*26947304SEvan Yan 	}
3242*26947304SEvan Yan 
3243*26947304SEvan Yan 	/*
3244*26947304SEvan Yan 	 * Allocate memory for the existing available plus one and then
3245*26947304SEvan Yan 	 * build it.
3246*26947304SEvan Yan 	 */
3247*26947304SEvan Yan 	new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
3248*26947304SEvan Yan 
3249*26947304SEvan Yan 	bcopy(avail_p, new_avail, alen);
3250*26947304SEvan Yan 	bcopy(newone, new_avail + alen, sizeof (*newone));
3251*26947304SEvan Yan 
3252*26947304SEvan Yan 	/* Write out the new "available" spec */
3253*26947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3254*26947304SEvan Yan 	    "available", (int *)new_avail,
3255*26947304SEvan Yan 	    (alen + sizeof (*newone))/sizeof (int));
3256*26947304SEvan Yan 
3257*26947304SEvan Yan 	kmem_free((caddr_t)new_avail, alen+sizeof (*newone));
3258*26947304SEvan Yan 
3259*26947304SEvan Yan 	/* Don't forget to free up memory from ddi_getlongprop */
3260*26947304SEvan Yan 	kmem_free((caddr_t)avail_p, alen);
3261*26947304SEvan Yan 
3262*26947304SEvan Yan 	return (PCICFG_SUCCESS);
3263*26947304SEvan Yan }
3264*26947304SEvan Yan 
3265*26947304SEvan Yan static int
3266*26947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
3267*26947304SEvan Yan     uint32_t base, uint32_t base_hi, uint_t reg_offset)
3268*26947304SEvan Yan {
3269*26947304SEvan Yan 	int		rlen;
3270*26947304SEvan Yan 	pci_regspec_t	*reg;
3271*26947304SEvan Yan 	uint32_t	hiword;
3272*26947304SEvan Yan 	pci_regspec_t	addition;
3273*26947304SEvan Yan 	uint_t		status;
3274*26947304SEvan Yan 
3275*26947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3276*26947304SEvan Yan 	    "reg", (caddr_t)&reg, &rlen);
3277*26947304SEvan Yan 
3278*26947304SEvan Yan 	switch (status) {
3279*26947304SEvan Yan 		case DDI_PROP_SUCCESS:
3280*26947304SEvan Yan 		break;
3281*26947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
3282*26947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
3283*26947304SEvan Yan 			return (PCICFG_FAILURE);
3284*26947304SEvan Yan 		default:
3285*26947304SEvan Yan 			/*
3286*26947304SEvan Yan 			 * Since the config space "reg" entry should have been
3287*26947304SEvan Yan 			 * created, we expect a "reg" property already
3288*26947304SEvan Yan 			 * present here.
3289*26947304SEvan Yan 			 */
3290*26947304SEvan Yan 			DEBUG0("no reg property\n");
3291*26947304SEvan Yan 			return (PCICFG_FAILURE);
3292*26947304SEvan Yan 	}
3293*26947304SEvan Yan 
3294*26947304SEvan Yan 	/*
3295*26947304SEvan Yan 	 * Build the regspec, then add it to the existing one(s)
3296*26947304SEvan Yan 	 */
3297*26947304SEvan Yan 
3298*26947304SEvan Yan 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
3299*26947304SEvan Yan 	    PCI_REG_DEV_G(reg->pci_phys_hi),
3300*26947304SEvan Yan 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
3301*26947304SEvan Yan 
3302*26947304SEvan Yan 	hiword |= PCI_REG_REL_M;
3303*26947304SEvan Yan 
3304*26947304SEvan Yan 	if (reg_offset == PCI_CONF_ROM) {
3305*26947304SEvan Yan 		hiword |= PCI_ADDR_MEM32;
3306*26947304SEvan Yan 
3307*26947304SEvan Yan 		base = PCI_BASE_ROM_ADDR_M & base;
3308*26947304SEvan Yan 	} else {
3309*26947304SEvan Yan 		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
3310*26947304SEvan Yan 			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
3311*26947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
3312*26947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & base)
3313*26947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
3314*26947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
3315*26947304SEvan Yan 			}
3316*26947304SEvan Yan 
3317*26947304SEvan Yan 			if (base & PCI_BASE_PREF_M)
3318*26947304SEvan Yan 				hiword |= PCI_REG_PF_M;
3319*26947304SEvan Yan 
3320*26947304SEvan Yan 			base = PCI_BASE_M_ADDR_M & base;
3321*26947304SEvan Yan 		} else {
3322*26947304SEvan Yan 			hiword |= PCI_ADDR_IO;
3323*26947304SEvan Yan 
3324*26947304SEvan Yan 			base = PCI_BASE_IO_ADDR_M & base;
3325*26947304SEvan Yan 			base_hi = 0;
3326*26947304SEvan Yan 		}
3327*26947304SEvan Yan 	}
3328*26947304SEvan Yan 
3329*26947304SEvan Yan 	addition.pci_phys_hi = hiword;
3330*26947304SEvan Yan 	addition.pci_phys_mid = base_hi;
3331*26947304SEvan Yan 	addition.pci_phys_low = base;
3332*26947304SEvan Yan 	addition.pci_size_hi = 0;
3333*26947304SEvan Yan 	addition.pci_size_low = size;
3334*26947304SEvan Yan 
3335*26947304SEvan Yan 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
3336*26947304SEvan Yan 
3337*26947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
3338*26947304SEvan Yan 
3339*26947304SEvan Yan 	return (pcicfg_update_assigned_prop(dip, &addition));
3340*26947304SEvan Yan }
3341*26947304SEvan Yan 
3342*26947304SEvan Yan static void
3343*26947304SEvan Yan pcicfg_device_on(ddi_acc_handle_t config_handle)
3344*26947304SEvan Yan {
3345*26947304SEvan Yan 	/*
3346*26947304SEvan Yan 	 * Enable memory, IO, and bus mastership
3347*26947304SEvan Yan 	 * XXX should we enable parity, SERR#,
3348*26947304SEvan Yan 	 * fast back-to-back, and addr. stepping?
3349*26947304SEvan Yan 	 */
3350*26947304SEvan Yan 	pci_config_put16(config_handle, PCI_CONF_COMM,
3351*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
3352*26947304SEvan Yan }
3353*26947304SEvan Yan 
3354*26947304SEvan Yan static void
3355*26947304SEvan Yan pcicfg_device_off(ddi_acc_handle_t config_handle)
3356*26947304SEvan Yan {
3357*26947304SEvan Yan 	/*
3358*26947304SEvan Yan 	 * Disable I/O and memory traffic through the bridge
3359*26947304SEvan Yan 	 */
3360*26947304SEvan Yan 	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
3361*26947304SEvan Yan }
3362*26947304SEvan Yan 
3363*26947304SEvan Yan /*
3364*26947304SEvan Yan  * Setup the basic 1275 properties based on information found in the config
3365*26947304SEvan Yan  * header of the PCI device
3366*26947304SEvan Yan  */
3367*26947304SEvan Yan static int
3368*26947304SEvan Yan pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
3369*26947304SEvan Yan 	uint8_t pcie_dev)
3370*26947304SEvan Yan {
3371*26947304SEvan Yan 	int ret;
3372*26947304SEvan Yan 	uint16_t val, cap_ptr;
3373*26947304SEvan Yan 	uint32_t wordval;
3374*26947304SEvan Yan 	uint8_t byteval;
3375*26947304SEvan Yan 
3376*26947304SEvan Yan 	/* These two exists only for non-bridges */
3377*26947304SEvan Yan 	if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
3378*26947304SEvan Yan 	    & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
3379*26947304SEvan Yan 		byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
3380*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3381*26947304SEvan Yan 		    "min-grant", byteval)) != DDI_SUCCESS) {
3382*26947304SEvan Yan 			return (ret);
3383*26947304SEvan Yan 		}
3384*26947304SEvan Yan 
3385*26947304SEvan Yan 		byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
3386*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3387*26947304SEvan Yan 		    "max-latency", byteval)) != DDI_SUCCESS) {
3388*26947304SEvan Yan 			return (ret);
3389*26947304SEvan Yan 		}
3390*26947304SEvan Yan 	}
3391*26947304SEvan Yan 
3392*26947304SEvan Yan 	/*
3393*26947304SEvan Yan 	 * These should always exist and have the value of the
3394*26947304SEvan Yan 	 * corresponding register value
3395*26947304SEvan Yan 	 */
3396*26947304SEvan Yan 	val = pci_config_get16(config_handle, PCI_CONF_VENID);
3397*26947304SEvan Yan 
3398*26947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3399*26947304SEvan Yan 	    "vendor-id", val)) != DDI_SUCCESS) {
3400*26947304SEvan Yan 		return (ret);
3401*26947304SEvan Yan 	}
3402*26947304SEvan Yan 	val = pci_config_get16(config_handle, PCI_CONF_DEVID);
3403*26947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3404*26947304SEvan Yan 	    "device-id", val)) != DDI_SUCCESS) {
3405*26947304SEvan Yan 		return (ret);
3406*26947304SEvan Yan 	}
3407*26947304SEvan Yan 	byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
3408*26947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3409*26947304SEvan Yan 	    "revision-id", byteval)) != DDI_SUCCESS) {
3410*26947304SEvan Yan 		return (ret);
3411*26947304SEvan Yan 	}
3412*26947304SEvan Yan 
3413*26947304SEvan Yan 	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
3414*26947304SEvan Yan 	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
3415*26947304SEvan Yan 
3416*26947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3417*26947304SEvan Yan 	    "class-code", wordval)) != DDI_SUCCESS) {
3418*26947304SEvan Yan 		return (ret);
3419*26947304SEvan Yan 	}
3420*26947304SEvan Yan 	/* devsel-speed starts at the 9th bit */
3421*26947304SEvan Yan 	val = (pci_config_get16(config_handle,
3422*26947304SEvan Yan 	    PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9;
3423*26947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3424*26947304SEvan Yan 	    "devsel-speed", val)) != DDI_SUCCESS) {
3425*26947304SEvan Yan 		return (ret);
3426*26947304SEvan Yan 	}
3427*26947304SEvan Yan 
3428*26947304SEvan Yan 	/*
3429*26947304SEvan Yan 	 * The next three are bits set in the status register.  The property is
3430*26947304SEvan Yan 	 * present (but with no value other than its own existence) if the bit
3431*26947304SEvan Yan 	 * is set, non-existent otherwise
3432*26947304SEvan Yan 	 */
3433*26947304SEvan Yan 	if ((!pcie_dev) &&
3434*26947304SEvan Yan 	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
3435*26947304SEvan Yan 	    PCI_STAT_FBBC)) {
3436*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3437*26947304SEvan Yan 		    "fast-back-to-back", 0)) != DDI_SUCCESS) {
3438*26947304SEvan Yan 			return (ret);
3439*26947304SEvan Yan 		}
3440*26947304SEvan Yan 	}
3441*26947304SEvan Yan 	if ((!pcie_dev) &&
3442*26947304SEvan Yan 	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
3443*26947304SEvan Yan 	    PCI_STAT_66MHZ)) {
3444*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3445*26947304SEvan Yan 		    "66mhz-capable", 0)) != DDI_SUCCESS) {
3446*26947304SEvan Yan 			return (ret);
3447*26947304SEvan Yan 		}
3448*26947304SEvan Yan 	}
3449*26947304SEvan Yan 	if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
3450*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3451*26947304SEvan Yan 		    "udf-supported", 0)) != DDI_SUCCESS) {
3452*26947304SEvan Yan 			return (ret);
3453*26947304SEvan Yan 		}
3454*26947304SEvan Yan 	}
3455*26947304SEvan Yan 
3456*26947304SEvan Yan 	/*
3457*26947304SEvan Yan 	 * These next three are optional and are not present
3458*26947304SEvan Yan 	 * if the corresponding register is zero.  If the value
3459*26947304SEvan Yan 	 * is non-zero then the property exists with the value
3460*26947304SEvan Yan 	 * of the register.
3461*26947304SEvan Yan 	 */
3462*26947304SEvan Yan 	if ((val = pci_config_get16(config_handle,
3463*26947304SEvan Yan 	    PCI_CONF_SUBVENID)) != 0) {
3464*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3465*26947304SEvan Yan 		    "subsystem-vendor-id", val)) != DDI_SUCCESS) {
3466*26947304SEvan Yan 			return (ret);
3467*26947304SEvan Yan 		}
3468*26947304SEvan Yan 	}
3469*26947304SEvan Yan 	if ((val = pci_config_get16(config_handle,
3470*26947304SEvan Yan 	    PCI_CONF_SUBSYSID)) != 0) {
3471*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3472*26947304SEvan Yan 		    "subsystem-id", val)) != DDI_SUCCESS) {
3473*26947304SEvan Yan 			return (ret);
3474*26947304SEvan Yan 		}
3475*26947304SEvan Yan 	}
3476*26947304SEvan Yan 	if ((val = pci_config_get16(config_handle,
3477*26947304SEvan Yan 	    PCI_CONF_CACHE_LINESZ)) != 0) {
3478*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3479*26947304SEvan Yan 		    "cache-line-size", val)) != DDI_SUCCESS) {
3480*26947304SEvan Yan 			return (ret);
3481*26947304SEvan Yan 		}
3482*26947304SEvan Yan 	}
3483*26947304SEvan Yan 
3484*26947304SEvan Yan 	/*
3485*26947304SEvan Yan 	 * If the Interrupt Pin register is non-zero then the
3486*26947304SEvan Yan 	 * interrupts property exists
3487*26947304SEvan Yan 	 */
3488*26947304SEvan Yan 	if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
3489*26947304SEvan Yan 		/*
3490*26947304SEvan Yan 		 * If interrupt pin is non-zero,
3491*26947304SEvan Yan 		 * record the interrupt line used
3492*26947304SEvan Yan 		 */
3493*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3494*26947304SEvan Yan 		    "interrupts", byteval)) != DDI_SUCCESS) {
3495*26947304SEvan Yan 			return (ret);
3496*26947304SEvan Yan 		}
3497*26947304SEvan Yan 	}
3498*26947304SEvan Yan 
3499*26947304SEvan Yan 	ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr);
3500*26947304SEvan Yan 
3501*26947304SEvan Yan 	if (pcie_dev && (ret == DDI_SUCCESS)) {
3502*26947304SEvan Yan 		val = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
3503*26947304SEvan Yan 		    PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
3504*26947304SEvan Yan 		/* if slot implemented, get physical slot number */
3505*26947304SEvan Yan 		if (val) {
3506*26947304SEvan Yan 			wordval = (PCI_CAP_GET32(config_handle, NULL,
3507*26947304SEvan Yan 			    cap_ptr, PCIE_SLOTCAP) >>
3508*26947304SEvan Yan 			    PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) &
3509*26947304SEvan Yan 			    PCIE_SLOTCAP_PHY_SLOT_NUM_MASK;
3510*26947304SEvan Yan 			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE,
3511*26947304SEvan Yan 			    dip, "physical-slot#", wordval))
3512*26947304SEvan Yan 			    != DDI_SUCCESS) {
3513*26947304SEvan Yan 				return (ret);
3514*26947304SEvan Yan 			}
3515*26947304SEvan Yan 		}
3516*26947304SEvan Yan 	}
3517*26947304SEvan Yan 	return (PCICFG_SUCCESS);
3518*26947304SEvan Yan }
3519*26947304SEvan Yan static int
3520*26947304SEvan Yan pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type,
3521*26947304SEvan Yan     int pbus, int sbus)
3522*26947304SEvan Yan {
3523*26947304SEvan Yan 	int ret;
3524*26947304SEvan Yan 	char device_type[8];
3525*26947304SEvan Yan 
3526*26947304SEvan Yan 	if (pcie_device_type)
3527*26947304SEvan Yan 		(void) strcpy(device_type, "pciex");
3528*26947304SEvan Yan 	else
3529*26947304SEvan Yan 		(void) strcpy(device_type, "pci");
3530*26947304SEvan Yan 
3531*26947304SEvan Yan 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
3532*26947304SEvan Yan 	    "device_type", device_type)) != DDI_SUCCESS) {
3533*26947304SEvan Yan 		return (ret);
3534*26947304SEvan Yan 	}
3535*26947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3536*26947304SEvan Yan 	    "#address-cells", 3)) != DDI_SUCCESS) {
3537*26947304SEvan Yan 		return (ret);
3538*26947304SEvan Yan 	}
3539*26947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3540*26947304SEvan Yan 	    "#size-cells", 2)) != DDI_SUCCESS) {
3541*26947304SEvan Yan 		return (ret);
3542*26947304SEvan Yan 	}
3543*26947304SEvan Yan 
3544*26947304SEvan Yan 	/*
3545*26947304SEvan Yan 	 * Create primary-bus and secondary-bus properties to be used
3546*26947304SEvan Yan 	 * to restore bus numbers in the pcicfg_setup_bridge() routine.
3547*26947304SEvan Yan 	 */
3548*26947304SEvan Yan 	if (pbus != -1 && sbus != -1) {
3549*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3550*26947304SEvan Yan 		    "primary-bus", pbus)) != DDI_SUCCESS) {
3551*26947304SEvan Yan 				return (ret);
3552*26947304SEvan Yan 		}
3553*26947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3554*26947304SEvan Yan 		    "secondary-bus", sbus)) != DDI_SUCCESS) {
3555*26947304SEvan Yan 				return (ret);
3556*26947304SEvan Yan 		}
3557*26947304SEvan Yan 	}
3558*26947304SEvan Yan 	return (PCICFG_SUCCESS);
3559*26947304SEvan Yan }
3560*26947304SEvan Yan 
3561*26947304SEvan Yan static int
3562*26947304SEvan Yan pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
3563*26947304SEvan Yan 	uint8_t pcie_dev)
3564*26947304SEvan Yan {
3565*26947304SEvan Yan 
3566*26947304SEvan Yan 	int		ret;
3567*26947304SEvan Yan 	char		*name;
3568*26947304SEvan Yan 	char		buffer[64], pprefix[8];
3569*26947304SEvan Yan 	uint16_t	classcode;
3570*26947304SEvan Yan 	uint8_t		revid, pif, pclass, psubclass;
3571*26947304SEvan Yan 	char		*compat[24];
3572*26947304SEvan Yan 	int		i;
3573*26947304SEvan Yan 	int		n;
3574*26947304SEvan Yan 	uint16_t		sub_vid, sub_sid, vid, did;
3575*26947304SEvan Yan 
3576*26947304SEvan Yan 	/* set the property prefix based on the device type */
3577*26947304SEvan Yan 	if (pcie_dev)
3578*26947304SEvan Yan 		(void) sprintf(pprefix, "pciex");
3579*26947304SEvan Yan 	else
3580*26947304SEvan Yan 		(void) sprintf(pprefix, "pci");
3581*26947304SEvan Yan 	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
3582*26947304SEvan Yan 	sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
3583*26947304SEvan Yan 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
3584*26947304SEvan Yan 	did = pci_config_get16(config_handle, PCI_CONF_DEVID);
3585*26947304SEvan Yan 	revid = pci_config_get8(config_handle, PCI_CONF_REVID);
3586*26947304SEvan Yan 	pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
3587*26947304SEvan Yan 	classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
3588*26947304SEvan Yan 	pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
3589*26947304SEvan Yan 	psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
3590*26947304SEvan Yan 
3591*26947304SEvan Yan 	/*
3592*26947304SEvan Yan 	 * NOTE: These are for both a child and PCI-PCI bridge node
3593*26947304SEvan Yan 	 */
3594*26947304SEvan Yan 
3595*26947304SEvan Yan 	/*
3596*26947304SEvan Yan 	 *	"name" property rule
3597*26947304SEvan Yan 	 *	--------------------
3598*26947304SEvan Yan 	 *
3599*26947304SEvan Yan 	 *
3600*26947304SEvan Yan 	 * |	  \svid |
3601*26947304SEvan Yan 	 * |	   \    |
3602*26947304SEvan Yan 	 * |	    \   |
3603*26947304SEvan Yan 	 * |	ssid \  |	=0		|	!= 0		|
3604*26947304SEvan Yan 	 * |------------|-----------------------|-----------------------|
3605*26947304SEvan Yan 	 * |		|			|			|
3606*26947304SEvan Yan 	 * |	=0	|	vid,did		|	svid,ssid	|
3607*26947304SEvan Yan 	 * |		|			|			|
3608*26947304SEvan Yan 	 * |------------|-----------------------|-----------------------|
3609*26947304SEvan Yan 	 * |		|			|			|
3610*26947304SEvan Yan 	 * |	!=0	|	svid,ssid	|	svid,ssid	|
3611*26947304SEvan Yan 	 * |		|			|			|
3612*26947304SEvan Yan 	 * |------------|-----------------------|-----------------------|
3613*26947304SEvan Yan 	 *
3614*26947304SEvan Yan 	 * where:
3615*26947304SEvan Yan 	 *    vid = vendor id
3616*26947304SEvan Yan 	 *    did = device id
3617*26947304SEvan Yan 	 *   svid = subsystem vendor id
3618*26947304SEvan Yan 	 *   ssid = subsystem id
3619*26947304SEvan Yan 	 */
3620*26947304SEvan Yan 
3621*26947304SEvan Yan 	if ((sub_sid != 0) || (sub_vid != 0)) {
3622*26947304SEvan Yan 		(void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid);
3623*26947304SEvan Yan 	} else {
3624*26947304SEvan Yan 		(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
3625*26947304SEvan Yan 	}
3626*26947304SEvan Yan 
3627*26947304SEvan Yan 	/*
3628*26947304SEvan Yan 	 * In some environments, trying to use "generic" 1275 names is
3629*26947304SEvan Yan 	 * not the convention.  In those cases use the name as created
3630*26947304SEvan Yan 	 * above.  In all the rest of the cases, check to see if there
3631*26947304SEvan Yan 	 * is a generic name first.
3632*26947304SEvan Yan 	 */
3633*26947304SEvan Yan #ifdef _DONT_USE_1275_GENERIC_NAMES
3634*26947304SEvan Yan 	name = buffer;
3635*26947304SEvan Yan #else
3636*26947304SEvan Yan 	if ((name = pcicfg_get_class_name(classcode)) == NULL) {
3637*26947304SEvan Yan 		/*
3638*26947304SEvan Yan 		 * Set name to the above fabricated name
3639*26947304SEvan Yan 		 */
3640*26947304SEvan Yan 		name = buffer;
3641*26947304SEvan Yan 	}
3642*26947304SEvan Yan #endif
3643*26947304SEvan Yan 
3644*26947304SEvan Yan 	/*
3645*26947304SEvan Yan 	 * The node name field needs to be filled in with the name
3646*26947304SEvan Yan 	 */
3647*26947304SEvan Yan 	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
3648*26947304SEvan Yan 		DEBUG0("Failed to set nodename for node\n");
3649*26947304SEvan Yan 		return (PCICFG_FAILURE);
3650*26947304SEvan Yan 	}
3651*26947304SEvan Yan 
3652*26947304SEvan Yan 	/*
3653*26947304SEvan Yan 	 * Create the compatible property as an array of pointers
3654*26947304SEvan Yan 	 * to strings.  Start with the buffer created above.
3655*26947304SEvan Yan 	 */
3656*26947304SEvan Yan 	n = 0;
3657*26947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3658*26947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
3659*26947304SEvan Yan 
3660*26947304SEvan Yan 	/*
3661*26947304SEvan Yan 	 * Setup 'compatible' as per the PCI2.1 bindings document.
3662*26947304SEvan Yan 	 *	pci[ex]VVVV,DDDD.SSSS.ssss.RR
3663*26947304SEvan Yan 	 *	pci[ex]VVVV,DDDD.SSSS.ssss
3664*26947304SEvan Yan 	 *	pciSSSS.ssss  -> not created for PCIe as per PCIe bindings
3665*26947304SEvan Yan 	 *	pci[ex]VVVV,DDDD.RR
3666*26947304SEvan Yan 	 *	pci[ex]VVVV,DDDD
3667*26947304SEvan Yan 	 *	pci[ex]class,CCSSPP
3668*26947304SEvan Yan 	 *	pci[ex]class,CCSS
3669*26947304SEvan Yan 	 */
3670*26947304SEvan Yan 
3671*26947304SEvan Yan 	/* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
3672*26947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix,  vid, did,
3673*26947304SEvan Yan 	    sub_vid, sub_sid, revid);
3674*26947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3675*26947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
3676*26947304SEvan Yan 
3677*26947304SEvan Yan 	/* pci[ex]VVVV,DDDD.SSSS.ssss */
3678*26947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid, did,
3679*26947304SEvan Yan 	    sub_vid, sub_sid);
3680*26947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3681*26947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
3682*26947304SEvan Yan 
3683*26947304SEvan Yan 	/* pciSSSS.ssss  -> not created for PCIe as per PCIe bindings */
3684*26947304SEvan Yan 	if (!pcie_dev) {
3685*26947304SEvan Yan 		(void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
3686*26947304SEvan Yan 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3687*26947304SEvan Yan 		(void) strcpy(compat[n++], buffer);
3688*26947304SEvan Yan 	}
3689*26947304SEvan Yan 
3690*26947304SEvan Yan 	/* pci[ex]VVVV,DDDD.RR */
3691*26947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x.%x", pprefix,  vid, did, revid);
3692*26947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3693*26947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
3694*26947304SEvan Yan 
3695*26947304SEvan Yan 	/* pci[ex]VVVV,DDDD */
3696*26947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
3697*26947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3698*26947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
3699*26947304SEvan Yan 
3700*26947304SEvan Yan 	/* pci[ex]class,CCSSPP */
3701*26947304SEvan Yan 	(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
3702*26947304SEvan Yan 	    pclass, psubclass, pif);
3703*26947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3704*26947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
3705*26947304SEvan Yan 
3706*26947304SEvan Yan 	/* pci[ex]class,CCSS */
3707*26947304SEvan Yan 	(void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
3708*26947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
3709*26947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
3710*26947304SEvan Yan 
3711*26947304SEvan Yan 	if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
3712*26947304SEvan Yan 	    "compatible", (char **)compat, n)) != DDI_SUCCESS) {
3713*26947304SEvan Yan 		return (ret);
3714*26947304SEvan Yan 	}
3715*26947304SEvan Yan 
3716*26947304SEvan Yan 	for (i = 0; i < n; i++) {
3717*26947304SEvan Yan 		kmem_free(compat[i], strlen(compat[i]) + 1);
3718*26947304SEvan Yan 	}
3719*26947304SEvan Yan 
3720*26947304SEvan Yan 	DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name);
3721*26947304SEvan Yan 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
3722*26947304SEvan Yan 	    "name", name)) != DDI_SUCCESS) {
3723*26947304SEvan Yan 
3724*26947304SEvan Yan 		DEBUG0("pcicfg_set_childnode_props - Unable to create name "
3725*26947304SEvan Yan 		    "property\n");
3726*26947304SEvan Yan 
3727*26947304SEvan Yan 		return (ret);
3728*26947304SEvan Yan 	}
3729*26947304SEvan Yan 
3730*26947304SEvan Yan 	return (PCICFG_SUCCESS);
3731*26947304SEvan Yan }
3732*26947304SEvan Yan 
3733*26947304SEvan Yan /*
3734*26947304SEvan Yan  * Program the bus numbers into the bridge
3735*26947304SEvan Yan  */
3736*26947304SEvan Yan 
3737*26947304SEvan Yan static void
3738*26947304SEvan Yan pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
3739*26947304SEvan Yan uint_t primary, uint_t secondary, uint_t subordinate)
3740*26947304SEvan Yan {
3741*26947304SEvan Yan 	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
3742*26947304SEvan Yan 	    subordinate);
3743*26947304SEvan Yan 	/*
3744*26947304SEvan Yan 	 * Primary bus#
3745*26947304SEvan Yan 	 */
3746*26947304SEvan Yan 	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
3747*26947304SEvan Yan 
3748*26947304SEvan Yan 	/*
3749*26947304SEvan Yan 	 * Secondary bus#
3750*26947304SEvan Yan 	 */
3751*26947304SEvan Yan 	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
3752*26947304SEvan Yan 
3753*26947304SEvan Yan 	/*
3754*26947304SEvan Yan 	 * Subordinate bus#
3755*26947304SEvan Yan 	 */
3756*26947304SEvan Yan 	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
3757*26947304SEvan Yan }
3758*26947304SEvan Yan 
3759*26947304SEvan Yan /*
3760*26947304SEvan Yan  * Put bridge registers into initial state
3761*26947304SEvan Yan  */
3762*26947304SEvan Yan static void
3763*26947304SEvan Yan pcicfg_setup_bridge(pcicfg_phdl_t *entry,
3764*26947304SEvan Yan     ddi_acc_handle_t handle, dev_info_t *dip)
3765*26947304SEvan Yan {
3766*26947304SEvan Yan 	int pbus, sbus;
3767*26947304SEvan Yan 
3768*26947304SEvan Yan 	/*
3769*26947304SEvan Yan 	 * The highest bus seen during probing is the max-subordinate bus
3770*26947304SEvan Yan 	 */
3771*26947304SEvan Yan 	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
3772*26947304SEvan Yan 
3773*26947304SEvan Yan 
3774*26947304SEvan Yan 	/*
3775*26947304SEvan Yan 	 * If there exists more than 1 downstream bridge, it
3776*26947304SEvan Yan 	 * will be reset by the below secondary bus reset which
3777*26947304SEvan Yan 	 * will clear the bus numbers assumed to be programmed in
3778*26947304SEvan Yan 	 * the pcicfg_probe_children() routine.  We therefore restore
3779*26947304SEvan Yan 	 * them here.
3780*26947304SEvan Yan 	 */
3781*26947304SEvan Yan 	if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) {
3782*26947304SEvan Yan 		pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
3783*26947304SEvan Yan 		    DDI_PROP_DONTPASS, "primary-bus", -1);
3784*26947304SEvan Yan 		sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
3785*26947304SEvan Yan 		    DDI_PROP_DONTPASS, "secondary-bus", -1);
3786*26947304SEvan Yan 		if (pbus != -1 && sbus != -1) {
3787*26947304SEvan Yan 			pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus);
3788*26947304SEvan Yan 			pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus);
3789*26947304SEvan Yan 		} else {
3790*26947304SEvan Yan 			cmn_err(CE_WARN, "Invalid Bridge number detected: \
3791*26947304SEvan Yan 			    %s%d: pbus = 0x%x, sbus = 0x%x",
3792*26947304SEvan Yan 			    ddi_get_name(dip), ddi_get_instance(dip), pbus,
3793*26947304SEvan Yan 			    sbus);
3794*26947304SEvan Yan 		}
3795*26947304SEvan Yan 	}
3796*26947304SEvan Yan 
3797*26947304SEvan Yan 	/*
3798*26947304SEvan Yan 	 * Reset the secondary bus
3799*26947304SEvan Yan 	 */
3800*26947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
3801*26947304SEvan Yan 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
3802*26947304SEvan Yan 
3803*26947304SEvan Yan 	drv_usecwait(100);
3804*26947304SEvan Yan 
3805*26947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
3806*26947304SEvan Yan 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
3807*26947304SEvan Yan 
3808*26947304SEvan Yan 	/*
3809*26947304SEvan Yan 	 * Program the memory base register with the
3810*26947304SEvan Yan 	 * start of the memory range
3811*26947304SEvan Yan 	 */
3812*26947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
3813*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
3814*26947304SEvan Yan 
3815*26947304SEvan Yan 	/*
3816*26947304SEvan Yan 	 * Program the I/O base register with the start of the I/O range
3817*26947304SEvan Yan 	 */
3818*26947304SEvan Yan 	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
3819*26947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
3820*26947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
3821*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
3822*26947304SEvan Yan 
3823*26947304SEvan Yan 	/*
3824*26947304SEvan Yan 	 * Clear status bits
3825*26947304SEvan Yan 	 */
3826*26947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
3827*26947304SEvan Yan 
3828*26947304SEvan Yan 	/*
3829*26947304SEvan Yan 	 * Turn off prefetchable range
3830*26947304SEvan Yan 	 */
3831*26947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
3832*26947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
3833*26947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
3834*26947304SEvan Yan 
3835*26947304SEvan Yan 	/*
3836*26947304SEvan Yan 	 * Needs to be set to this value
3837*26947304SEvan Yan 	 */
3838*26947304SEvan Yan 	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
3839*26947304SEvan Yan 
3840*26947304SEvan Yan 	/*
3841*26947304SEvan Yan 	 * After a Reset, we need to wait 2^25 clock cycles before the
3842*26947304SEvan Yan 	 * first Configuration access.  The worst case is 33MHz, which
3843*26947304SEvan Yan 	 * is a 1 second wait.
3844*26947304SEvan Yan 	 */
3845*26947304SEvan Yan 	drv_usecwait(pcicfg_sec_reset_delay);
3846*26947304SEvan Yan 
3847*26947304SEvan Yan }
3848*26947304SEvan Yan 
3849*26947304SEvan Yan static void
3850*26947304SEvan Yan pcicfg_update_bridge(pcicfg_phdl_t *entry,
3851*26947304SEvan Yan 	ddi_acc_handle_t handle)
3852*26947304SEvan Yan {
3853*26947304SEvan Yan 	uint_t length;
3854*26947304SEvan Yan 
3855*26947304SEvan Yan 	/*
3856*26947304SEvan Yan 	 * Program the memory limit register with the end of the memory range
3857*26947304SEvan Yan 	 */
3858*26947304SEvan Yan 
3859*26947304SEvan Yan 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
3860*26947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last,
3861*26947304SEvan Yan 	    PCICFG_MEMGRAN));
3862*26947304SEvan Yan 
3863*26947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
3864*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(
3865*26947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last,
3866*26947304SEvan Yan 	    PCICFG_MEMGRAN))));
3867*26947304SEvan Yan 	/*
3868*26947304SEvan Yan 	 * Since this is a bridge, the rest of this range will
3869*26947304SEvan Yan 	 * be responded to by the bridge.  We have to round up
3870*26947304SEvan Yan 	 * so no other device claims it.
3871*26947304SEvan Yan 	 */
3872*26947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->memory_last,
3873*26947304SEvan Yan 	    PCICFG_MEMGRAN) - entry->memory_last)) > 0) {
3874*26947304SEvan Yan 		(void) pcicfg_get_mem(entry, length, NULL);
3875*26947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of "
3876*26947304SEvan Yan 		    "the bridge (mem)\n", length);
3877*26947304SEvan Yan 	}
3878*26947304SEvan Yan 
3879*26947304SEvan Yan 	/*
3880*26947304SEvan Yan 	 * Program the I/O limit register with the end of the I/O range
3881*26947304SEvan Yan 	 */
3882*26947304SEvan Yan 	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
3883*26947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(
3884*26947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
3885*26947304SEvan Yan 	    PCICFG_IOGRAN)))));
3886*26947304SEvan Yan 
3887*26947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
3888*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
3889*26947304SEvan Yan 	    PCICFG_IOGRAN))));
3890*26947304SEvan Yan 
3891*26947304SEvan Yan 	/*
3892*26947304SEvan Yan 	 * Same as above for I/O space. Since this is a
3893*26947304SEvan Yan 	 * bridge, the rest of this range will be responded
3894*26947304SEvan Yan 	 * to by the bridge.  We have to round up so no
3895*26947304SEvan Yan 	 * other device claims it.
3896*26947304SEvan Yan 	 */
3897*26947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->io_last,
3898*26947304SEvan Yan 	    PCICFG_IOGRAN) - entry->io_last)) > 0) {
3899*26947304SEvan Yan 		(void) pcicfg_get_io(entry, length, NULL);
3900*26947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of "
3901*26947304SEvan Yan 		    "the bridge (I/O)\n",  length);
3902*26947304SEvan Yan 	}
3903*26947304SEvan Yan }
3904*26947304SEvan Yan 
3905*26947304SEvan Yan /*ARGSUSED*/
3906*26947304SEvan Yan static void
3907*26947304SEvan Yan pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
3908*26947304SEvan Yan 	pcicfg_err_regs_t *regs)
3909*26947304SEvan Yan {
3910*26947304SEvan Yan 	uint16_t val;
3911*26947304SEvan Yan 
3912*26947304SEvan Yan 	/* disable SERR generated in the context of Master Aborts. */
3913*26947304SEvan Yan 	regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM);
3914*26947304SEvan Yan 	val &= ~PCI_COMM_SERR_ENABLE;
3915*26947304SEvan Yan 	pci_config_put16(h, PCI_CONF_COMM, val);
3916*26947304SEvan Yan 	regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL);
3917*26947304SEvan Yan 	val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
3918*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL, val);
3919*26947304SEvan Yan 	/* clear any current pending errors */
3920*26947304SEvan Yan 	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
3921*26947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
3922*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
3923*26947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
3924*26947304SEvan Yan 	/* if we are a PCIe device, disable the generation of UR, CE and NFE */
3925*26947304SEvan Yan 	if (regs->pcie_dev) {
3926*26947304SEvan Yan 		uint16_t devctl;
3927*26947304SEvan Yan 		uint16_t cap_ptr;
3928*26947304SEvan Yan 
3929*26947304SEvan Yan 		if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
3930*26947304SEvan Yan 		    DDI_FAILURE)
3931*26947304SEvan Yan 			return;
3932*26947304SEvan Yan 
3933*26947304SEvan Yan 		regs->pcie_cap_off = cap_ptr;
3934*26947304SEvan Yan 		regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr,
3935*26947304SEvan Yan 		    PCIE_DEVCTL);
3936*26947304SEvan Yan 		devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN |
3937*26947304SEvan Yan 		    PCIE_DEVCTL_CE_REPORTING_EN |
3938*26947304SEvan Yan 		    PCIE_DEVCTL_NFE_REPORTING_EN |
3939*26947304SEvan Yan 		    PCIE_DEVCTL_FE_REPORTING_EN);
3940*26947304SEvan Yan 		PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl);
3941*26947304SEvan Yan 	}
3942*26947304SEvan Yan }
3943*26947304SEvan Yan 
3944*26947304SEvan Yan /*ARGSUSED*/
3945*26947304SEvan Yan static void
3946*26947304SEvan Yan pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
3947*26947304SEvan Yan 	pcicfg_err_regs_t *regs)
3948*26947304SEvan Yan {
3949*26947304SEvan Yan 	/* clear any pending errors */
3950*26947304SEvan Yan 	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
3951*26947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
3952*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
3953*26947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
3954*26947304SEvan Yan 
3955*26947304SEvan Yan 	/* restore original settings */
3956*26947304SEvan Yan 	if (regs->pcie_dev) {
3957*26947304SEvan Yan 		pcie_clear_errors(dip);
3958*26947304SEvan Yan 		pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
3959*26947304SEvan Yan 		    regs->devctl);
3960*26947304SEvan Yan 	}
3961*26947304SEvan Yan 
3962*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl);
3963*26947304SEvan Yan 	pci_config_put16(h, PCI_CONF_COMM, regs->cmd);
3964*26947304SEvan Yan 
3965*26947304SEvan Yan }
3966*26947304SEvan Yan 
3967*26947304SEvan Yan static int
3968*26947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
3969*26947304SEvan Yan     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
3970*26947304SEvan Yan {
3971*26947304SEvan Yan 	dev_info_t		*new_child;
3972*26947304SEvan Yan 	ddi_acc_handle_t	config_handle;
3973*26947304SEvan Yan 	uint8_t			header_type, pcie_dev = 0;
3974*26947304SEvan Yan 	int			ret;
3975*26947304SEvan Yan 	pcicfg_err_regs_t	regs;
3976*26947304SEvan Yan 
3977*26947304SEvan Yan 	/*
3978*26947304SEvan Yan 	 * This node will be put immediately below
3979*26947304SEvan Yan 	 * "parent". Allocate a blank device node.  It will either
3980*26947304SEvan Yan 	 * be filled in or freed up based on further probing.
3981*26947304SEvan Yan 	 */
3982*26947304SEvan Yan 	/*
3983*26947304SEvan Yan 	 * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c
3984*26947304SEvan Yan 	 * ndi_devi_alloc() is called as ndi_devi_alloc_sleep()
3985*26947304SEvan Yan 	 */
3986*26947304SEvan Yan 	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
3987*26947304SEvan Yan 	    (pnode_t)DEVI_SID_NODEID, &new_child)
3988*26947304SEvan Yan 	    != NDI_SUCCESS) {
3989*26947304SEvan Yan 		DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n");
3990*26947304SEvan Yan 		return (PCICFG_FAILURE);
3991*26947304SEvan Yan 	}
3992*26947304SEvan Yan 
3993*26947304SEvan Yan 	if (pcicfg_add_config_reg(new_child, bus,
3994*26947304SEvan Yan 	    device, func) != DDI_SUCCESS) {
3995*26947304SEvan Yan 		DEBUG0("pcicfg_probe_children():"
3996*26947304SEvan Yan 		    "Failed to add candidate REG\n");
3997*26947304SEvan Yan 		goto failedconfig;
3998*26947304SEvan Yan 	}
3999*26947304SEvan Yan 
4000*26947304SEvan Yan 	if ((ret = pcicfg_config_setup(new_child, &config_handle))
4001*26947304SEvan Yan 	    != PCICFG_SUCCESS) {
4002*26947304SEvan Yan 		if (ret == PCICFG_NODEVICE) {
4003*26947304SEvan Yan 			(void) ndi_devi_free(new_child);
4004*26947304SEvan Yan 			return (ret);
4005*26947304SEvan Yan 		}
4006*26947304SEvan Yan 		DEBUG0("pcicfg_probe_children():"
4007*26947304SEvan Yan 		    "Failed to setup config space\n");
4008*26947304SEvan Yan 		goto failedconfig;
4009*26947304SEvan Yan 	}
4010*26947304SEvan Yan 
4011*26947304SEvan Yan 	/*
4012*26947304SEvan Yan 	 * As soon as we have access to config space,
4013*26947304SEvan Yan 	 * turn off device. It will get turned on
4014*26947304SEvan Yan 	 * later (after memory is assigned).
4015*26947304SEvan Yan 	 */
4016*26947304SEvan Yan 	(void) pcicfg_device_off(config_handle);
4017*26947304SEvan Yan 
4018*26947304SEvan Yan 	/* check if we are PCIe device */
4019*26947304SEvan Yan 	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
4020*26947304SEvan Yan 	    == DDI_SUCCESS) {
4021*26947304SEvan Yan 		DEBUG0("PCIe device detected\n");
4022*26947304SEvan Yan 		pcie_dev = 1;
4023*26947304SEvan Yan 	}
4024*26947304SEvan Yan 
4025*26947304SEvan Yan 	/*
4026*26947304SEvan Yan 	 * Set 1275 properties common to all devices
4027*26947304SEvan Yan 	 */
4028*26947304SEvan Yan 	if (pcicfg_set_standard_props(new_child, config_handle,
4029*26947304SEvan Yan 	    pcie_dev) != PCICFG_SUCCESS) {
4030*26947304SEvan Yan 		DEBUG0("Failed to set standard properties\n");
4031*26947304SEvan Yan 		goto failedchild;
4032*26947304SEvan Yan 	}
4033*26947304SEvan Yan 
4034*26947304SEvan Yan 	/*
4035*26947304SEvan Yan 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
4036*26947304SEvan Yan 	 */
4037*26947304SEvan Yan 	if (pcicfg_set_childnode_props(new_child, config_handle,
4038*26947304SEvan Yan 	    pcie_dev) != PCICFG_SUCCESS) {
4039*26947304SEvan Yan 		goto failedchild;
4040*26947304SEvan Yan 	}
4041*26947304SEvan Yan 
4042*26947304SEvan Yan 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
4043*26947304SEvan Yan 
4044*26947304SEvan Yan 	/*
4045*26947304SEvan Yan 	 * If this is not a multi-function card only probe function zero.
4046*26947304SEvan Yan 	 */
4047*26947304SEvan Yan 	if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
4048*26947304SEvan Yan 
4049*26947304SEvan Yan 		(void) pcicfg_config_teardown(&config_handle);
4050*26947304SEvan Yan 		(void) ndi_devi_free(new_child);
4051*26947304SEvan Yan 		return (PCICFG_NODEVICE);
4052*26947304SEvan Yan 	}
4053*26947304SEvan Yan 
4054*26947304SEvan Yan 	DEBUG1("---Vendor ID = [0x%x]\n",
4055*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID));
4056*26947304SEvan Yan 	DEBUG1("---Device ID = [0x%x]\n",
4057*26947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
4058*26947304SEvan Yan 
4059*26947304SEvan Yan 	/*
4060*26947304SEvan Yan 	 * Attach the child to its parent
4061*26947304SEvan Yan 	 */
4062*26947304SEvan Yan 	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
4063*26947304SEvan Yan 
4064*26947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
4065*26947304SEvan Yan 
4066*26947304SEvan Yan 		DEBUG3("--Bridge found bus [0x%x] device"
4067*26947304SEvan Yan 		    "[0x%x] func [0x%x]\n", bus, device, func);
4068*26947304SEvan Yan 
4069*26947304SEvan Yan 		/* Only support read-only probe for leaf device */
4070*26947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
4071*26947304SEvan Yan 			goto failedchild;
4072*26947304SEvan Yan 
4073*26947304SEvan Yan 		if (pcicfg_probe_bridge(new_child, config_handle,
4074*26947304SEvan Yan 		    bus, highest_bus) != PCICFG_SUCCESS) {
4075*26947304SEvan Yan 			(void) pcicfg_free_bridge_resources(new_child);
4076*26947304SEvan Yan 			goto failedchild;
4077*26947304SEvan Yan 		}
4078*26947304SEvan Yan 
4079*26947304SEvan Yan 	} else {
4080*26947304SEvan Yan 
4081*26947304SEvan Yan 		DEBUG3("--Leaf device found bus [0x%x] device"
4082*26947304SEvan Yan 		    "[0x%x] func [0x%x]\n",
4083*26947304SEvan Yan 		    bus, device, func);
4084*26947304SEvan Yan 
4085*26947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY) {
4086*26947304SEvan Yan 			/*
4087*26947304SEvan Yan 			 * with read-only probe, don't do any resource
4088*26947304SEvan Yan 			 * allocation, just read the BARs and update props.
4089*26947304SEvan Yan 			 */
4090*26947304SEvan Yan 			ret = pcicfg_populate_props_from_bar(new_child,
4091*26947304SEvan Yan 			    config_handle);
4092*26947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
4093*26947304SEvan Yan 				goto failedchild;
4094*26947304SEvan Yan 
4095*26947304SEvan Yan 			/*
4096*26947304SEvan Yan 			 * for readonly probe "assigned-addresses" property
4097*26947304SEvan Yan 			 * has already been setup by reading the BAR, here
4098*26947304SEvan Yan 			 * just substract the resource from its parent here.
4099*26947304SEvan Yan 			 */
4100*26947304SEvan Yan 			ret = pcicfg_device_assign_readonly(new_child);
4101*26947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
4102*26947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child,
4103*26947304SEvan Yan 				    flags);
4104*26947304SEvan Yan 				goto failedchild;
4105*26947304SEvan Yan 			}
4106*26947304SEvan Yan 		} else {
4107*26947304SEvan Yan 			/*
4108*26947304SEvan Yan 			 * update "reg" property by sizing the BARs.
4109*26947304SEvan Yan 			 */
4110*26947304SEvan Yan 			ret = pcicfg_populate_reg_props(new_child,
4111*26947304SEvan Yan 			    config_handle);
4112*26947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
4113*26947304SEvan Yan 				goto failedchild;
4114*26947304SEvan Yan 
4115*26947304SEvan Yan 			/* now allocate & program the resources */
4116*26947304SEvan Yan 			ret = pcicfg_device_assign(new_child);
4117*26947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
4118*26947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child,
4119*26947304SEvan Yan 				    flags);
4120*26947304SEvan Yan 				goto failedchild;
4121*26947304SEvan Yan 			}
4122*26947304SEvan Yan 		}
4123*26947304SEvan Yan 
4124*26947304SEvan Yan 		(void) ndi_devi_bind_driver(new_child, 0);
4125*26947304SEvan Yan 	}
4126*26947304SEvan Yan 
4127*26947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
4128*26947304SEvan Yan 	return (PCICFG_SUCCESS);
4129*26947304SEvan Yan 
4130*26947304SEvan Yan failedchild:
4131*26947304SEvan Yan 
4132*26947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
4133*26947304SEvan Yan 
4134*26947304SEvan Yan failedconfig:
4135*26947304SEvan Yan 
4136*26947304SEvan Yan 	(void) ndi_devi_free(new_child);
4137*26947304SEvan Yan 	return (PCICFG_FAILURE);
4138*26947304SEvan Yan }
4139*26947304SEvan Yan 
4140*26947304SEvan Yan /*
4141*26947304SEvan Yan  * Sizing the BARs and update "reg" property
4142*26947304SEvan Yan  */
4143*26947304SEvan Yan static int
4144*26947304SEvan Yan pcicfg_populate_reg_props(dev_info_t *new_child,
4145*26947304SEvan Yan     ddi_acc_handle_t config_handle)
4146*26947304SEvan Yan {
4147*26947304SEvan Yan 	int		i;
4148*26947304SEvan Yan 	uint32_t	request;
4149*26947304SEvan Yan 
4150*26947304SEvan Yan 	i = PCI_CONF_BASE0;
4151*26947304SEvan Yan 
4152*26947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
4153*26947304SEvan Yan 
4154*26947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
4155*26947304SEvan Yan 
4156*26947304SEvan Yan 		request = pci_config_get32(config_handle, i);
4157*26947304SEvan Yan 		/*
4158*26947304SEvan Yan 		 * If its a zero length, don't do
4159*26947304SEvan Yan 		 * any programming.
4160*26947304SEvan Yan 		 */
4161*26947304SEvan Yan 		if (request != 0) {
4162*26947304SEvan Yan 			/*
4163*26947304SEvan Yan 			 * Add to the "reg" property
4164*26947304SEvan Yan 			 */
4165*26947304SEvan Yan 			if (pcicfg_update_reg_prop(new_child,
4166*26947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
4167*26947304SEvan Yan 				goto failedchild;
4168*26947304SEvan Yan 			}
4169*26947304SEvan Yan 		} else {
4170*26947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for "
4171*26947304SEvan Yan 			    "[0x0]=[0x0](32)\n", i);
4172*26947304SEvan Yan 			i += 4;
4173*26947304SEvan Yan 			continue;
4174*26947304SEvan Yan 		}
4175*26947304SEvan Yan 
4176*26947304SEvan Yan 		/*
4177*26947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
4178*26947304SEvan Yan 		 */
4179*26947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
4180*26947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
4181*26947304SEvan Yan 			    "[0x%x]=[0x%x] (64)\n",
4182*26947304SEvan Yan 			    i, request,
4183*26947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
4184*26947304SEvan Yan 			i += 8;
4185*26947304SEvan Yan 		} else {
4186*26947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
4187*26947304SEvan Yan 			    "[0x%x]=[0x%x](32)\n",
4188*26947304SEvan Yan 			    i, request,
4189*26947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
4190*26947304SEvan Yan 			i += 4;
4191*26947304SEvan Yan 		}
4192*26947304SEvan Yan 	}
4193*26947304SEvan Yan 
4194*26947304SEvan Yan 	/*
4195*26947304SEvan Yan 	 * Get the ROM size and create register for it
4196*26947304SEvan Yan 	 */
4197*26947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
4198*26947304SEvan Yan 
4199*26947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
4200*26947304SEvan Yan 	/*
4201*26947304SEvan Yan 	 * If its a zero length, don't do
4202*26947304SEvan Yan 	 * any programming.
4203*26947304SEvan Yan 	 */
4204*26947304SEvan Yan 
4205*26947304SEvan Yan 	if (request != 0) {
4206*26947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
4207*26947304SEvan Yan 		    PCI_CONF_ROM, request,
4208*26947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
4209*26947304SEvan Yan 		/*
4210*26947304SEvan Yan 		 * Add to the "reg" property
4211*26947304SEvan Yan 		 */
4212*26947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child,
4213*26947304SEvan Yan 		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
4214*26947304SEvan Yan 			goto failedchild;
4215*26947304SEvan Yan 		}
4216*26947304SEvan Yan 	}
4217*26947304SEvan Yan 
4218*26947304SEvan Yan 
4219*26947304SEvan Yan 	return (PCICFG_SUCCESS);
4220*26947304SEvan Yan 
4221*26947304SEvan Yan failedchild:
4222*26947304SEvan Yan 	return (PCICFG_FAILURE);
4223*26947304SEvan Yan }
4224*26947304SEvan Yan 
4225*26947304SEvan Yan static int
4226*26947304SEvan Yan pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
4227*26947304SEvan Yan     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
4228*26947304SEvan Yan {
4229*26947304SEvan Yan 	dev_info_t		*new_child;
4230*26947304SEvan Yan 	int8_t			header_type;
4231*26947304SEvan Yan 	int			ret;
4232*26947304SEvan Yan 	ddi_acc_handle_t	h, ph;
4233*26947304SEvan Yan 	int			error = 0;
4234*26947304SEvan Yan 	extern int		pcicfg_dont_interpret;
4235*26947304SEvan Yan 	pcicfg_err_regs_t	parent_regs, regs;
4236*26947304SEvan Yan 	char			*status_prop = NULL;
4237*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
4238*26947304SEvan Yan 	struct pci_ops_bus_args	po;
4239*26947304SEvan Yan 	fco_handle_t		c;
4240*26947304SEvan Yan 	char			unit_address[64];
4241*26947304SEvan Yan 	int			fcode_size = 0;
4242*26947304SEvan Yan 	uchar_t			*fcode_addr;
4243*26947304SEvan Yan 	uint64_t		mem_answer, mem_alen;
4244*26947304SEvan Yan 	pci_regspec_t		p;
4245*26947304SEvan Yan 	int32_t			request;
4246*26947304SEvan Yan 	ndi_ra_request_t	req;
4247*26947304SEvan Yan 	int16_t			vendor_id, device_id;
4248*26947304SEvan Yan #endif
4249*26947304SEvan Yan 
4250*26947304SEvan Yan 	/*
4251*26947304SEvan Yan 	 * check if our parent is of type pciex.
4252*26947304SEvan Yan 	 * if so, program config space to disable error msgs during probe.
4253*26947304SEvan Yan 	 */
4254*26947304SEvan Yan 	if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs)
4255*26947304SEvan Yan 	    == DDI_SUCCESS) {
4256*26947304SEvan Yan 		DEBUG0("PCI/PCIe parent detected. Disable errors.\n");
4257*26947304SEvan Yan 		/*
4258*26947304SEvan Yan 		 * disable parent generating URs or SERR#s during probing
4259*26947304SEvan Yan 		 * alone.
4260*26947304SEvan Yan 		 */
4261*26947304SEvan Yan 		if (pci_config_setup(parent, &ph) != DDI_SUCCESS)
4262*26947304SEvan Yan 			return (DDI_FAILURE);
4263*26947304SEvan Yan 
4264*26947304SEvan Yan 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
4265*26947304SEvan Yan 			pcicfg_disable_bridge_probe_err(parent,
4266*26947304SEvan Yan 			    ph, &parent_regs);
4267*26947304SEvan Yan 		}
4268*26947304SEvan Yan 	}
4269*26947304SEvan Yan 
4270*26947304SEvan Yan 	/*
4271*26947304SEvan Yan 	 * This node will be put immediately below
4272*26947304SEvan Yan 	 * "parent". Allocate a blank device node.  It will either
4273*26947304SEvan Yan 	 * be filled in or freed up based on further probing.
4274*26947304SEvan Yan 	 */
4275*26947304SEvan Yan 
4276*26947304SEvan Yan 	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
4277*26947304SEvan Yan 	    (pnode_t)DEVI_SID_NODEID, &new_child)
4278*26947304SEvan Yan 	    != NDI_SUCCESS) {
4279*26947304SEvan Yan 		DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n");
4280*26947304SEvan Yan 		/* return (PCICFG_FAILURE); */
4281*26947304SEvan Yan 		ret = PCICFG_FAILURE;
4282*26947304SEvan Yan 		goto failed2;
4283*26947304SEvan Yan 	}
4284*26947304SEvan Yan 
4285*26947304SEvan Yan 	/*
4286*26947304SEvan Yan 	 * Create a dummy reg property.  This will be replaced with
4287*26947304SEvan Yan 	 * a real reg property when fcode completes or if we need to
4288*26947304SEvan Yan 	 * produce one by hand.
4289*26947304SEvan Yan 	 */
4290*26947304SEvan Yan 	if (pcicfg_add_config_reg(new_child, bus,
4291*26947304SEvan Yan 	    device, func) != DDI_SUCCESS) {
4292*26947304SEvan Yan 		ret = PCICFG_FAILURE;
4293*26947304SEvan Yan 		goto failed3;
4294*26947304SEvan Yan 	}
4295*26947304SEvan Yan #ifdef	EFCODE21554
4296*26947304SEvan Yan 	if ((ret = pcicfg_config_setup(new_child, &h))
4297*26947304SEvan Yan 	    != PCICFG_SUCCESS) {
4298*26947304SEvan Yan 		DEBUG0("pcicfg_fcode_probe():"
4299*26947304SEvan Yan 		    "Failed to setup config space\n");
4300*26947304SEvan Yan 		ret = PCICFG_NODEVICE;
4301*26947304SEvan Yan 		goto failed3;
4302*26947304SEvan Yan 	}
4303*26947304SEvan Yan 
4304*26947304SEvan Yan #else
4305*26947304SEvan Yan 	p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
4306*26947304SEvan Yan 	p.pci_phys_mid = p.pci_phys_low = 0;
4307*26947304SEvan Yan 	p.pci_size_hi = p.pci_size_low = 0;
4308*26947304SEvan Yan 
4309*26947304SEvan Yan 	/*
4310*26947304SEvan Yan 	 * Map in configuration space (temporarily)
4311*26947304SEvan Yan 	 */
4312*26947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4313*26947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
4314*26947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4315*26947304SEvan Yan 
4316*26947304SEvan Yan 	if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) {
4317*26947304SEvan Yan 		DEBUG0("pcicfg_fcode_probe():"
4318*26947304SEvan Yan 		    "Failed to setup config space\n");
4319*26947304SEvan Yan 		ret = PCICFG_NODEVICE;
4320*26947304SEvan Yan 		goto failed3;
4321*26947304SEvan Yan 	}
4322*26947304SEvan Yan 
4323*26947304SEvan Yan 	/*
4324*26947304SEvan Yan 	 * First use ddi_peek16 so that if there is not a device there,
4325*26947304SEvan Yan 	 * a bus error will not cause a panic.
4326*26947304SEvan Yan 	 */
4327*26947304SEvan Yan 	v = virt + PCI_CONF_VENID;
4328*26947304SEvan Yan 	if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) {
4329*26947304SEvan Yan 		DEBUG0("Can not read Vendor ID");
4330*26947304SEvan Yan 		pcicfg_unmap_phys(&h, &p);
4331*26947304SEvan Yan 		ret = PCICFG_NODEVICE;
4332*26947304SEvan Yan 		goto failed3;
4333*26947304SEvan Yan 	}
4334*26947304SEvan Yan #endif
4335*26947304SEvan Yan 	DEBUG0("fcode_probe: conf space mapped.\n");
4336*26947304SEvan Yan 	/*
4337*26947304SEvan Yan 	 * As soon as we have access to config space,
4338*26947304SEvan Yan 	 * turn off device. It will get turned on
4339*26947304SEvan Yan 	 * later (after memory is assigned).
4340*26947304SEvan Yan 	 */
4341*26947304SEvan Yan 	(void) pcicfg_device_off(h);
4342*26947304SEvan Yan 
4343*26947304SEvan Yan 	/* check if we are PCIe device */
4344*26947304SEvan Yan 	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
4345*26947304SEvan Yan 	    == DDI_SUCCESS) {
4346*26947304SEvan Yan 		/*EMPTY*/
4347*26947304SEvan Yan 		DEBUG0("PCI/PCIe device detected\n");
4348*26947304SEvan Yan 	}
4349*26947304SEvan Yan 
4350*26947304SEvan Yan 	/*
4351*26947304SEvan Yan 	 * Set 1275 properties common to all devices
4352*26947304SEvan Yan 	 */
4353*26947304SEvan Yan 	if (pcicfg_set_standard_props(new_child,
4354*26947304SEvan Yan 	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
4355*26947304SEvan Yan 		DEBUG0("Failed to set standard properties\n");
4356*26947304SEvan Yan 		goto failed;
4357*26947304SEvan Yan 	}
4358*26947304SEvan Yan 
4359*26947304SEvan Yan 	/*
4360*26947304SEvan Yan 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
4361*26947304SEvan Yan 	 */
4362*26947304SEvan Yan 	if (pcicfg_set_childnode_props(new_child,
4363*26947304SEvan Yan 	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
4364*26947304SEvan Yan 		ret = PCICFG_FAILURE;
4365*26947304SEvan Yan 		goto failed;
4366*26947304SEvan Yan 	}
4367*26947304SEvan Yan 
4368*26947304SEvan Yan 	header_type = pci_config_get8(h, PCI_CONF_HEADER);
4369*26947304SEvan Yan 
4370*26947304SEvan Yan 	/*
4371*26947304SEvan Yan 	 * If this is not a multi-function card only probe function zero.
4372*26947304SEvan Yan 	 */
4373*26947304SEvan Yan 	if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) {
4374*26947304SEvan Yan 
4375*26947304SEvan Yan 		ret = PCICFG_NODEVICE;
4376*26947304SEvan Yan 		goto failed;
4377*26947304SEvan Yan 	}
4378*26947304SEvan Yan 
4379*26947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
4380*26947304SEvan Yan 
4381*26947304SEvan Yan 		/*
4382*26947304SEvan Yan 		 * XXX - Transparent bridges are handled differently
4383*26947304SEvan Yan 		 * than other devices with regards to fcode.  Since
4384*26947304SEvan Yan 		 * no transparent bridge currently ships with fcode,
4385*26947304SEvan Yan 		 * there is no reason to try to extract it from its rom
4386*26947304SEvan Yan 		 * or call the fcode interpreter to try to load a drop-in.
4387*26947304SEvan Yan 		 * If fcode is developed to handle transparent bridges,
4388*26947304SEvan Yan 		 * this code will have to change.
4389*26947304SEvan Yan 		 */
4390*26947304SEvan Yan 
4391*26947304SEvan Yan 		DEBUG3("--Bridge found bus [0x%x] device"
4392*26947304SEvan Yan 		    "[0x%x] func [0x%x]\n", bus, device, func);
4393*26947304SEvan Yan 
4394*26947304SEvan Yan 		/* Only support read-only probe for leaf device */
4395*26947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
4396*26947304SEvan Yan 			goto failed;
4397*26947304SEvan Yan 
4398*26947304SEvan Yan 		if ((ret = pcicfg_probe_bridge(new_child, h,
4399*26947304SEvan Yan 		    bus, highest_bus)) != PCICFG_SUCCESS)
4400*26947304SEvan Yan 			(void) pcicfg_free_bridge_resources(new_child);
4401*26947304SEvan Yan 		goto done;
4402*26947304SEvan Yan 	} else {
4403*26947304SEvan Yan 
4404*26947304SEvan Yan 		DEBUG3("--Leaf device found bus [0x%x] device"
4405*26947304SEvan Yan 		    "[0x%x] func [0x%x]\n",
4406*26947304SEvan Yan 		    bus, device, func);
4407*26947304SEvan Yan 
4408*26947304SEvan Yan 		/*
4409*26947304SEvan Yan 		 * link in tree, but don't bind driver
4410*26947304SEvan Yan 		 * We don't have compatible property yet
4411*26947304SEvan Yan 		 */
4412*26947304SEvan Yan 		(void) i_ndi_config_node(new_child, DS_LINKED, 0);
4413*26947304SEvan Yan 
4414*26947304SEvan Yan 		/* XXX for now, don't run Fcode in read-only probe. */
4415*26947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
4416*26947304SEvan Yan 			goto no_fcode;
4417*26947304SEvan Yan 
4418*26947304SEvan Yan 		if (pci_config_get8(h, PCI_CONF_IPIN)) {
4419*26947304SEvan Yan 			pci_config_put8(h, PCI_CONF_ILINE, 0xf);
4420*26947304SEvan Yan 		}
4421*26947304SEvan Yan 
4422*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
4423*26947304SEvan Yan 		/*
4424*26947304SEvan Yan 		 * Some platforms (x86) don't run fcode, so don't interpret
4425*26947304SEvan Yan 		 * fcode that might be in the ROM.
4426*26947304SEvan Yan 		 */
4427*26947304SEvan Yan 		if (pcicfg_dont_interpret == 0) {
4428*26947304SEvan Yan 
4429*26947304SEvan Yan 			/* This platform supports fcode */
4430*26947304SEvan Yan 
4431*26947304SEvan Yan 			vendor_id = pci_config_get16(h, PCI_CONF_VENID);
4432*26947304SEvan Yan 			device_id = pci_config_get16(h, PCI_CONF_DEVID);
4433*26947304SEvan Yan 
4434*26947304SEvan Yan 			/*
4435*26947304SEvan Yan 			 * Get the ROM size and create register for it
4436*26947304SEvan Yan 			 */
4437*26947304SEvan Yan 			pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe);
4438*26947304SEvan Yan 
4439*26947304SEvan Yan 			request = pci_config_get32(h, PCI_CONF_ROM);
4440*26947304SEvan Yan 
4441*26947304SEvan Yan 			/*
4442*26947304SEvan Yan 			 * If its a zero length, don't do
4443*26947304SEvan Yan 			 * any programming.
4444*26947304SEvan Yan 			 */
4445*26947304SEvan Yan 
4446*26947304SEvan Yan 			if (request != 0) {
4447*26947304SEvan Yan 				/*
4448*26947304SEvan Yan 				 * Add resource to assigned-addresses.
4449*26947304SEvan Yan 				 */
4450*26947304SEvan Yan 				if (pcicfg_fcode_assign_bars(h, new_child,
4451*26947304SEvan Yan 				    bus, device, func, request, &p)
4452*26947304SEvan Yan 				    != PCICFG_SUCCESS) {
4453*26947304SEvan Yan 					DEBUG0("Failed to assign addresses to "
4454*26947304SEvan Yan 					    "implemented BARs");
4455*26947304SEvan Yan 					ret = PCICFG_FAILURE;
4456*26947304SEvan Yan 					goto failed;
4457*26947304SEvan Yan 				}
4458*26947304SEvan Yan 
4459*26947304SEvan Yan 				/* Turn device on */
4460*26947304SEvan Yan 				(void) pcicfg_device_on(h);
4461*26947304SEvan Yan 
4462*26947304SEvan Yan 				/*
4463*26947304SEvan Yan 				 * Attempt to load fcode.
4464*26947304SEvan Yan 				 */
4465*26947304SEvan Yan 				(void) pcicfg_load_fcode(new_child, bus, device,
4466*26947304SEvan Yan 				    func, vendor_id, device_id, &fcode_addr,
4467*26947304SEvan Yan 				    &fcode_size, PCICFG_LOADDR(mem_answer),
4468*26947304SEvan Yan 				    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
4469*26947304SEvan Yan 
4470*26947304SEvan Yan 				/* Turn device off */
4471*26947304SEvan Yan 				(void) pcicfg_device_off(h);
4472*26947304SEvan Yan 
4473*26947304SEvan Yan 				/*
4474*26947304SEvan Yan 				 * Free the ROM resources.
4475*26947304SEvan Yan 				 */
4476*26947304SEvan Yan 				(void) pcicfg_free_resource(new_child, p, 0);
4477*26947304SEvan Yan 
4478*26947304SEvan Yan 				DEBUG2("configure: fcode addr %lx size %x\n",
4479*26947304SEvan Yan 				    fcode_addr, fcode_size);
4480*26947304SEvan Yan 
4481*26947304SEvan Yan 				/*
4482*26947304SEvan Yan 				 * Create the fcode-rom-offset property.  The
4483*26947304SEvan Yan 				 * buffer containing the fcode always starts
4484*26947304SEvan Yan 				 * with 0xF1, so the fcode offset is zero.
4485*26947304SEvan Yan 				 */
4486*26947304SEvan Yan 				if (ndi_prop_update_int(DDI_DEV_T_NONE,
4487*26947304SEvan Yan 				    new_child, "fcode-rom-offset", 0)
4488*26947304SEvan Yan 				    != DDI_SUCCESS) {
4489*26947304SEvan Yan 					DEBUG0("Failed to create "
4490*26947304SEvan Yan 					    "fcode-rom-offset property\n");
4491*26947304SEvan Yan 					ret = PCICFG_FAILURE;
4492*26947304SEvan Yan 					goto failed;
4493*26947304SEvan Yan 				}
4494*26947304SEvan Yan 			} else {
4495*26947304SEvan Yan 				DEBUG0("There is no Expansion ROM\n");
4496*26947304SEvan Yan 				fcode_addr = NULL;
4497*26947304SEvan Yan 				fcode_size = 0;
4498*26947304SEvan Yan 			}
4499*26947304SEvan Yan 
4500*26947304SEvan Yan 			/*
4501*26947304SEvan Yan 			 * Fill in the bus specific arguments. For
4502*26947304SEvan Yan 			 * PCI, it is the config address.
4503*26947304SEvan Yan 			 */
4504*26947304SEvan Yan 			po.config_address =
4505*26947304SEvan Yan 			    PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
4506*26947304SEvan Yan 
4507*26947304SEvan Yan 			DEBUG1("config_address=%x\n", po.config_address);
4508*26947304SEvan Yan 
4509*26947304SEvan Yan 			/*
4510*26947304SEvan Yan 			 * Build unit address.
4511*26947304SEvan Yan 			 */
4512*26947304SEvan Yan 			(void) sprintf(unit_address, "%x,%x", device, func);
4513*26947304SEvan Yan 
4514*26947304SEvan Yan 			DEBUG3("pci_fc_ops_alloc_handle ap=%lx "
4515*26947304SEvan Yan 			    "new device=%lx unit address=%s\n",
4516*26947304SEvan Yan 			    parent, new_child, unit_address);
4517*26947304SEvan Yan 
4518*26947304SEvan Yan 			c = pci_fc_ops_alloc_handle(parent, new_child,
4519*26947304SEvan Yan 			    fcode_addr, fcode_size, unit_address, &po);
4520*26947304SEvan Yan 
4521*26947304SEvan Yan 			DEBUG0("calling fcode_interpreter()\n");
4522*26947304SEvan Yan 
4523*26947304SEvan Yan 			DEBUG3("Before int DIP=%lx binding name %s major %d\n",
4524*26947304SEvan Yan 			    new_child, ddi_binding_name(new_child),
4525*26947304SEvan Yan 			    ddi_driver_major(new_child));
4526*26947304SEvan Yan 
4527*26947304SEvan Yan 			error = fcode_interpreter(parent, &pci_fc_ops, c);
4528*26947304SEvan Yan 
4529*26947304SEvan Yan 			DEBUG1("returned from fcode_interpreter() - "
4530*26947304SEvan Yan 			    "returned %x\n", error);
4531*26947304SEvan Yan 
4532*26947304SEvan Yan 			pci_fc_ops_free_handle(c);
4533*26947304SEvan Yan 
4534*26947304SEvan Yan 			DEBUG1("fcode size = %x\n", fcode_size);
4535*26947304SEvan Yan 			/*
4536*26947304SEvan Yan 			 * We don't need the fcode anymore. While allocating
4537*26947304SEvan Yan 			 * we had rounded up to a page size.
4538*26947304SEvan Yan 			 */
4539*26947304SEvan Yan 			if (fcode_size) {
4540*26947304SEvan Yan 				kmem_free(fcode_addr, ptob(btopr(fcode_size)));
4541*26947304SEvan Yan 			}
4542*26947304SEvan Yan 		} else {
4543*26947304SEvan Yan 			/* This platform does not support fcode */
4544*26947304SEvan Yan 
4545*26947304SEvan Yan 			DEBUG0("NOT calling fcode_interpreter()\n");
4546*26947304SEvan Yan 		}
4547*26947304SEvan Yan 
4548*26947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */
4549*26947304SEvan Yan 
4550*26947304SEvan Yan 		if ((error == 0) && (pcicfg_dont_interpret == 0)) {
4551*26947304SEvan Yan 			/*
4552*26947304SEvan Yan 			 * The interpreter completed successfully.
4553*26947304SEvan Yan 			 * We need to redo the resources based on the new reg
4554*26947304SEvan Yan 			 * property.
4555*26947304SEvan Yan 			 */
4556*26947304SEvan Yan 			DEBUG3("DIP=%lx binding name %s major %d\n", new_child,
4557*26947304SEvan Yan 			    ddi_binding_name(new_child),
4558*26947304SEvan Yan 			    ddi_driver_major(new_child));
4559*26947304SEvan Yan 
4560*26947304SEvan Yan 			/*
4561*26947304SEvan Yan 			 * Readjust resources specified by reg property.
4562*26947304SEvan Yan 			 */
4563*26947304SEvan Yan 			if (pcicfg_alloc_new_resources(new_child) ==
4564*26947304SEvan Yan 			    PCICFG_FAILURE) {
4565*26947304SEvan Yan 				ret = PCICFG_FAILURE;
4566*26947304SEvan Yan 				goto failed;
4567*26947304SEvan Yan 			}
4568*26947304SEvan Yan 
4569*26947304SEvan Yan 			/*
4570*26947304SEvan Yan 			 * At this stage, there should be enough info to pull
4571*26947304SEvan Yan 			 * the status property if it exists.
4572*26947304SEvan Yan 			 */
4573*26947304SEvan Yan 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY,
4574*26947304SEvan Yan 			    new_child, NULL, "status", &status_prop) ==
4575*26947304SEvan Yan 			    DDI_PROP_SUCCESS) {
4576*26947304SEvan Yan 				if ((strncmp("disabled", status_prop, 8) ==
4577*26947304SEvan Yan 				    0) || (strncmp("fail", status_prop, 4) ==
4578*26947304SEvan Yan 				    0)) {
4579*26947304SEvan Yan 					ret = PCICFG_FAILURE;
4580*26947304SEvan Yan 					ddi_prop_free(status_prop);
4581*26947304SEvan Yan 					goto failed;
4582*26947304SEvan Yan 				} else {
4583*26947304SEvan Yan 					ddi_prop_free(status_prop);
4584*26947304SEvan Yan 				}
4585*26947304SEvan Yan 			}
4586*26947304SEvan Yan 
4587*26947304SEvan Yan 			ret = PCICFG_SUCCESS;
4588*26947304SEvan Yan 			/* no fcode, bind driver now */
4589*26947304SEvan Yan 			(void) ndi_devi_bind_driver(new_child, 0);
4590*26947304SEvan Yan 
4591*26947304SEvan Yan 			goto done;
4592*26947304SEvan Yan 		} else if ((error != FC_NO_FCODE) &&
4593*26947304SEvan Yan 		    (pcicfg_dont_interpret == 0))  {
4594*26947304SEvan Yan 			/*
4595*26947304SEvan Yan 			 * The interpreter located fcode, but had an error in
4596*26947304SEvan Yan 			 * processing. Cleanup and fail the operation.
4597*26947304SEvan Yan 			 */
4598*26947304SEvan Yan 			DEBUG0("Interpreter detected fcode failure\n");
4599*26947304SEvan Yan 			(void) pcicfg_free_resources(new_child, flags);
4600*26947304SEvan Yan 			ret = PCICFG_FAILURE;
4601*26947304SEvan Yan 			goto failed;
4602*26947304SEvan Yan 		} else {
4603*26947304SEvan Yan no_fcode:
4604*26947304SEvan Yan 			/*
4605*26947304SEvan Yan 			 * Either the interpreter failed with FC_NO_FCODE or we
4606*26947304SEvan Yan 			 * chose not to run the interpreter
4607*26947304SEvan Yan 			 * (pcicfg_dont_interpret).
4608*26947304SEvan Yan 			 *
4609*26947304SEvan Yan 			 * If the interpreter failed because there was no
4610*26947304SEvan Yan 			 * dropin, then we need to probe the device ourself.
4611*26947304SEvan Yan 			 */
4612*26947304SEvan Yan 
4613*26947304SEvan Yan 			/*
4614*26947304SEvan Yan 			 * Free any resources that may have been assigned
4615*26947304SEvan Yan 			 * during fcode loading/execution since we need
4616*26947304SEvan Yan 			 * to start over.
4617*26947304SEvan Yan 			 */
4618*26947304SEvan Yan 			(void) pcicfg_free_resources(new_child, flags);
4619*26947304SEvan Yan 
4620*26947304SEvan Yan #ifdef	EFCODE21554
4621*26947304SEvan Yan 			pcicfg_config_teardown(&h);
4622*26947304SEvan Yan #else
4623*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
4624*26947304SEvan Yan #endif
4625*26947304SEvan Yan 			(void) ndi_devi_free(new_child);
4626*26947304SEvan Yan 
4627*26947304SEvan Yan 			DEBUG0("No Drop-in Probe device ourself\n");
4628*26947304SEvan Yan 
4629*26947304SEvan Yan 			ret = pcicfg_probe_children(parent, bus, device, func,
4630*26947304SEvan Yan 			    highest_bus, flags);
4631*26947304SEvan Yan 
4632*26947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
4633*26947304SEvan Yan 				DEBUG0("Could not self probe child\n");
4634*26947304SEvan Yan 				goto failed2;
4635*26947304SEvan Yan 			}
4636*26947304SEvan Yan 
4637*26947304SEvan Yan 			/*
4638*26947304SEvan Yan 			 * We successfully self probed the device.
4639*26947304SEvan Yan 			 */
4640*26947304SEvan Yan 			if ((new_child = pcicfg_devi_find(
4641*26947304SEvan Yan 			    parent, device, func)) == NULL) {
4642*26947304SEvan Yan 				DEBUG0("Did'nt find device node "
4643*26947304SEvan Yan 				    "just created\n");
4644*26947304SEvan Yan 				ret = PCICFG_FAILURE;
4645*26947304SEvan Yan 				goto failed2;
4646*26947304SEvan Yan 			}
4647*26947304SEvan Yan #ifdef	EFCODE21554
4648*26947304SEvan Yan 			/*
4649*26947304SEvan Yan 			 * Till now, we have detected a non transparent bridge
4650*26947304SEvan Yan 			 * (ntbridge) as a part of the generic probe code and
4651*26947304SEvan Yan 			 * configured only one configuration
4652*26947304SEvan Yan 			 * header which is the side facing the host bus.
4653*26947304SEvan Yan 			 * Now, configure the other side and create children.
4654*26947304SEvan Yan 			 *
4655*26947304SEvan Yan 			 * To make the process simpler, lets load the device
4656*26947304SEvan Yan 			 * driver for the non transparent bridge as this is a
4657*26947304SEvan Yan 			 * Solaris bundled driver, and use its configuration map
4658*26947304SEvan Yan 			 * services rather than programming it here.
4659*26947304SEvan Yan 			 * If the driver is not bundled into Solaris, it must be
4660*26947304SEvan Yan 			 * first loaded and configured before performing any
4661*26947304SEvan Yan 			 * hotplug operations.
4662*26947304SEvan Yan 			 *
4663*26947304SEvan Yan 			 * This not only makes the code simpler but also more
4664*26947304SEvan Yan 			 * generic.
4665*26947304SEvan Yan 			 *
4666*26947304SEvan Yan 			 * So here we go.
4667*26947304SEvan Yan 			 */
4668*26947304SEvan Yan 			if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) {
4669*26947304SEvan Yan 
4670*26947304SEvan Yan 				DEBUG0("Found nontransparent bridge.\n");
4671*26947304SEvan Yan 
4672*26947304SEvan Yan 				ret = pcicfg_configure_ntbridge(new_child,
4673*26947304SEvan Yan 				    bus, device);
4674*26947304SEvan Yan 			}
4675*26947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
4676*26947304SEvan Yan 				/*
4677*26947304SEvan Yan 				 * Bridge configure failed. Free up the self
4678*26947304SEvan Yan 				 * probed entry. The bus resource allocation
4679*26947304SEvan Yan 				 * maps need to be cleaned up to prevent
4680*26947304SEvan Yan 				 * warnings on retries of the failed configure.
4681*26947304SEvan Yan 				 */
4682*26947304SEvan Yan 				(void) pcicfg_ntbridge_unconfigure(new_child);
4683*26947304SEvan Yan 				(void) pcicfg_teardown_device(new_child, flags);
4684*26947304SEvan Yan 			}
4685*26947304SEvan Yan #endif
4686*26947304SEvan Yan 			goto done2;
4687*26947304SEvan Yan 		}
4688*26947304SEvan Yan 	}
4689*26947304SEvan Yan done:
4690*26947304SEvan Yan failed:
4691*26947304SEvan Yan #ifdef	EFCODE21554
4692*26947304SEvan Yan 	pcicfg_config_teardown(&h);
4693*26947304SEvan Yan #else
4694*26947304SEvan Yan 	pcicfg_unmap_phys(&h, &p);
4695*26947304SEvan Yan #endif
4696*26947304SEvan Yan failed3:
4697*26947304SEvan Yan 	if (ret != PCICFG_SUCCESS)
4698*26947304SEvan Yan 		(void) ndi_devi_free(new_child);
4699*26947304SEvan Yan done2:
4700*26947304SEvan Yan failed2:
4701*26947304SEvan Yan 	if (parent_regs.pcie_dev) {
4702*26947304SEvan Yan 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
4703*26947304SEvan Yan 			pcicfg_enable_bridge_probe_err(parent,
4704*26947304SEvan Yan 			    ph, &parent_regs);
4705*26947304SEvan Yan 		}
4706*26947304SEvan Yan 		pci_config_teardown(&ph);
4707*26947304SEvan Yan 	}
4708*26947304SEvan Yan 	return (ret);
4709*26947304SEvan Yan }
4710*26947304SEvan Yan 
4711*26947304SEvan Yan /*
4712*26947304SEvan Yan  * Read the BARs and update properties. Used in virtual hotplug.
4713*26947304SEvan Yan  */
4714*26947304SEvan Yan static int
4715*26947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child,
4716*26947304SEvan Yan     ddi_acc_handle_t config_handle)
4717*26947304SEvan Yan {
4718*26947304SEvan Yan 	uint32_t request, base, base_hi, size;
4719*26947304SEvan Yan 	int i;
4720*26947304SEvan Yan 
4721*26947304SEvan Yan 	i = PCI_CONF_BASE0;
4722*26947304SEvan Yan 
4723*26947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
4724*26947304SEvan Yan 		/*
4725*26947304SEvan Yan 		 * determine the size of the address space
4726*26947304SEvan Yan 		 */
4727*26947304SEvan Yan 		base = pci_config_get32(config_handle, i);
4728*26947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
4729*26947304SEvan Yan 		request = pci_config_get32(config_handle, i);
4730*26947304SEvan Yan 		pci_config_put32(config_handle, i, base);
4731*26947304SEvan Yan 
4732*26947304SEvan Yan 		/*
4733*26947304SEvan Yan 		 * If its a zero length, don't do any programming.
4734*26947304SEvan Yan 		 */
4735*26947304SEvan Yan 		if (request != 0) {
4736*26947304SEvan Yan 			/*
4737*26947304SEvan Yan 			 * Add to the "reg" property
4738*26947304SEvan Yan 			 */
4739*26947304SEvan Yan 			if (pcicfg_update_reg_prop(new_child,
4740*26947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
4741*26947304SEvan Yan 				goto failedchild;
4742*26947304SEvan Yan 			}
4743*26947304SEvan Yan 
4744*26947304SEvan Yan 			if ((PCI_BASE_SPACE_IO & request) == 0 &&
4745*26947304SEvan Yan 			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
4746*26947304SEvan Yan 				base_hi = pci_config_get32(config_handle, i+4);
4747*26947304SEvan Yan 			} else {
4748*26947304SEvan Yan 				base_hi = 0;
4749*26947304SEvan Yan 			}
4750*26947304SEvan Yan 			/*
4751*26947304SEvan Yan 			 * Add to "assigned-addresses" property
4752*26947304SEvan Yan 			 */
4753*26947304SEvan Yan 			size = (~(PCI_BASE_M_ADDR_M & request))+1;
4754*26947304SEvan Yan 			if (pcicfg_update_assigned_prop_value(new_child,
4755*26947304SEvan Yan 			    size, base, base_hi, i) != PCICFG_SUCCESS) {
4756*26947304SEvan Yan 				goto failedchild;
4757*26947304SEvan Yan 			}
4758*26947304SEvan Yan 		} else {
4759*26947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for "
4760*26947304SEvan Yan 			"[0x0]=[0x0](32)\n", i);
4761*26947304SEvan Yan 			i += 4;
4762*26947304SEvan Yan 			continue;
4763*26947304SEvan Yan 		}
4764*26947304SEvan Yan 
4765*26947304SEvan Yan 		/*
4766*26947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
4767*26947304SEvan Yan 		 */
4768*26947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
4769*26947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
4770*26947304SEvan Yan 			"[0x%x]=[0x%x] (64)\n",
4771*26947304SEvan Yan 			    i, request,
4772*26947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
4773*26947304SEvan Yan 			i += 8;
4774*26947304SEvan Yan 		} else {
4775*26947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
4776*26947304SEvan Yan 			"[0x%x]=[0x%x](32)\n",
4777*26947304SEvan Yan 			    i, request,
4778*26947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
4779*26947304SEvan Yan 			i += 4;
4780*26947304SEvan Yan 		}
4781*26947304SEvan Yan 	}
4782*26947304SEvan Yan 
4783*26947304SEvan Yan 	/*
4784*26947304SEvan Yan 	 * Get the ROM size and create register for it
4785*26947304SEvan Yan 	 */
4786*26947304SEvan Yan 	base = pci_config_get32(config_handle, PCI_CONF_ROM);
4787*26947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
4788*26947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
4789*26947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, base);
4790*26947304SEvan Yan 
4791*26947304SEvan Yan 	/*
4792*26947304SEvan Yan 	 * If its a zero length, don't do
4793*26947304SEvan Yan 	 * any programming.
4794*26947304SEvan Yan 	 */
4795*26947304SEvan Yan 	if (request != 0) {
4796*26947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
4797*26947304SEvan Yan 		    PCI_CONF_ROM, request,
4798*26947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
4799*26947304SEvan Yan 		/*
4800*26947304SEvan Yan 		 * Add to the "reg" property
4801*26947304SEvan Yan 		 */
4802*26947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child,
4803*26947304SEvan Yan 		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
4804*26947304SEvan Yan 			goto failedchild;
4805*26947304SEvan Yan 		}
4806*26947304SEvan Yan 		/*
4807*26947304SEvan Yan 		 * Add to "assigned-addresses" property
4808*26947304SEvan Yan 		 */
4809*26947304SEvan Yan 		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
4810*26947304SEvan Yan 		if (pcicfg_update_assigned_prop_value(new_child, size,
4811*26947304SEvan Yan 		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
4812*26947304SEvan Yan 			goto failedchild;
4813*26947304SEvan Yan 		}
4814*26947304SEvan Yan 	}
4815*26947304SEvan Yan 
4816*26947304SEvan Yan 	return (PCICFG_SUCCESS);
4817*26947304SEvan Yan 
4818*26947304SEvan Yan failedchild:
4819*26947304SEvan Yan 	return (PCICFG_FAILURE);
4820*26947304SEvan Yan }
4821*26947304SEvan Yan 
4822*26947304SEvan Yan static int
4823*26947304SEvan Yan pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
4824*26947304SEvan Yan     uint_t *highest_bus)
4825*26947304SEvan Yan {
4826*26947304SEvan Yan 	uint64_t next_bus;
4827*26947304SEvan Yan 	uint_t new_bus, num_slots;
4828*26947304SEvan Yan 	ndi_ra_request_t req;
4829*26947304SEvan Yan 	int rval, i, j;
4830*26947304SEvan Yan 	uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end;
4831*26947304SEvan Yan 	uint64_t io_answer, io_base, io_alen, io_size, io_end;
4832*26947304SEvan Yan 	uint64_t round_answer, round_len;
4833*26947304SEvan Yan 	pcicfg_range_t range[PCICFG_RANGE_LEN];
4834*26947304SEvan Yan 	int bus_range[2];
4835*26947304SEvan Yan 	pcicfg_phdl_t phdl;
4836*26947304SEvan Yan 	int count;
4837*26947304SEvan Yan 	uint64_t pcibus_base, pcibus_alen;
4838*26947304SEvan Yan 	uint64_t max_bus;
4839*26947304SEvan Yan 	uint8_t pcie_device_type = 0;
4840*26947304SEvan Yan 	dev_info_t *new_device;
4841*26947304SEvan Yan 	int trans_device;
4842*26947304SEvan Yan 	int ari_mode = B_FALSE;
4843*26947304SEvan Yan 	int max_function = PCICFG_MAX_FUNCTION;
4844*26947304SEvan Yan 
4845*26947304SEvan Yan 	/*
4846*26947304SEvan Yan 	 * Set "device_type" to "pci", the actual type will be set later
4847*26947304SEvan Yan 	 * by pcicfg_set_busnode_props() below. This is needed as the
4848*26947304SEvan Yan 	 * pcicfg_ra_free() below would update "available" property based
4849*26947304SEvan Yan 	 * on "device_type".
4850*26947304SEvan Yan 	 *
4851*26947304SEvan Yan 	 * This code can be removed later after PCI configurator is changed
4852*26947304SEvan Yan 	 * to use PCIRM, which automatically update properties upon allocation
4853*26947304SEvan Yan 	 * and free, at that time we'll be able to remove the code inside
4854*26947304SEvan Yan 	 * ndi_ra_alloc/free() which currently updates "available" property
4855*26947304SEvan Yan 	 * for pci/pcie devices in pcie fabric.
4856*26947304SEvan Yan 	 */
4857*26947304SEvan Yan 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
4858*26947304SEvan Yan 	    "device_type", "pci") != DDI_SUCCESS) {
4859*26947304SEvan Yan 		DEBUG0("Failed to set \"device_type\" props\n");
4860*26947304SEvan Yan 		return (PCICFG_FAILURE);
4861*26947304SEvan Yan 	}
4862*26947304SEvan Yan 
4863*26947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
4864*26947304SEvan Yan 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
4865*26947304SEvan Yan 	req.ra_boundbase = 0;
4866*26947304SEvan Yan 	req.ra_boundlen = PCICFG_MAX_BUS_DEPTH;
4867*26947304SEvan Yan 	req.ra_len = PCICFG_MAX_BUS_DEPTH;
4868*26947304SEvan Yan 	req.ra_align_mask = 0;  /* no alignment needed */
4869*26947304SEvan Yan 
4870*26947304SEvan Yan 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
4871*26947304SEvan Yan 	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
4872*26947304SEvan Yan 
4873*26947304SEvan Yan 	if (rval != NDI_SUCCESS) {
4874*26947304SEvan Yan 		if (rval == NDI_RA_PARTIAL_REQ) {
4875*26947304SEvan Yan 			/*EMPTY*/
4876*26947304SEvan Yan 			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
4877*26947304SEvan Yan 		} else {
4878*26947304SEvan Yan 			DEBUG0(
4879*26947304SEvan Yan 			    "Failed to allocate bus range for bridge\n");
4880*26947304SEvan Yan 			return (PCICFG_FAILURE);
4881*26947304SEvan Yan 		}
4882*26947304SEvan Yan 	}
4883*26947304SEvan Yan 
4884*26947304SEvan Yan 	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
4885*26947304SEvan Yan 	    pcibus_base, pcibus_alen);
4886*26947304SEvan Yan 
4887*26947304SEvan Yan 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
4888*26947304SEvan Yan 	    == NDI_FAILURE) {
4889*26947304SEvan Yan 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
4890*26947304SEvan Yan 		return (PCICFG_FAILURE);
4891*26947304SEvan Yan 	}
4892*26947304SEvan Yan 
4893*26947304SEvan Yan 	/*
4894*26947304SEvan Yan 	 * Put available bus range into the pool.
4895*26947304SEvan Yan 	 * Take the first one for this bridge to use and don't give
4896*26947304SEvan Yan 	 * to child.
4897*26947304SEvan Yan 	 */
4898*26947304SEvan Yan 	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
4899*26947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
4900*26947304SEvan Yan 
4901*26947304SEvan Yan 	next_bus = pcibus_base;
4902*26947304SEvan Yan 	max_bus = pcibus_base + pcibus_alen - 1;
4903*26947304SEvan Yan 
4904*26947304SEvan Yan 	new_bus = next_bus;
4905*26947304SEvan Yan 
4906*26947304SEvan Yan 	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
4907*26947304SEvan Yan 
4908*26947304SEvan Yan 	/* Keep track of highest bus for subordinate bus programming */
4909*26947304SEvan Yan 	*highest_bus = new_bus;
4910*26947304SEvan Yan 
4911*26947304SEvan Yan 	/*
4912*26947304SEvan Yan 	 * Allocate Memory Space for Bridge
4913*26947304SEvan Yan 	 */
4914*26947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
4915*26947304SEvan Yan 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
4916*26947304SEvan Yan 	req.ra_boundbase = 0;
4917*26947304SEvan Yan 	/*
4918*26947304SEvan Yan 	 * Note: To support a 32b system, boundlen and len need to be
4919*26947304SEvan Yan 	 * 32b quantities
4920*26947304SEvan Yan 	 */
4921*26947304SEvan Yan 	req.ra_boundlen = PCICFG_4GIG_LIMIT + 1;
4922*26947304SEvan Yan 	req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */
4923*26947304SEvan Yan 	req.ra_align_mask =
4924*26947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
4925*26947304SEvan Yan 
4926*26947304SEvan Yan 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
4927*26947304SEvan Yan 	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
4928*26947304SEvan Yan 
4929*26947304SEvan Yan 	if (rval != NDI_SUCCESS) {
4930*26947304SEvan Yan 		if (rval == NDI_RA_PARTIAL_REQ) {
4931*26947304SEvan Yan 			/*EMPTY*/
4932*26947304SEvan Yan 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
4933*26947304SEvan Yan 		} else {
4934*26947304SEvan Yan 			DEBUG0(
4935*26947304SEvan Yan 			    "Failed to allocate memory for bridge\n");
4936*26947304SEvan Yan 			return (PCICFG_FAILURE);
4937*26947304SEvan Yan 		}
4938*26947304SEvan Yan 	}
4939*26947304SEvan Yan 
4940*26947304SEvan Yan 	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
4941*26947304SEvan Yan 	    PCICFG_HIADDR(mem_answer),
4942*26947304SEvan Yan 	    PCICFG_LOADDR(mem_answer),
4943*26947304SEvan Yan 	    mem_alen);
4944*26947304SEvan Yan 
4945*26947304SEvan Yan 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
4946*26947304SEvan Yan 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
4947*26947304SEvan Yan 		return (PCICFG_FAILURE);
4948*26947304SEvan Yan 	}
4949*26947304SEvan Yan 
4950*26947304SEvan Yan 	/*
4951*26947304SEvan Yan 	 * Put available memory into the pool.
4952*26947304SEvan Yan 	 */
4953*26947304SEvan Yan 	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
4954*26947304SEvan Yan 	    NDI_RA_PASS);
4955*26947304SEvan Yan 
4956*26947304SEvan Yan 	mem_base = mem_answer;
4957*26947304SEvan Yan 
4958*26947304SEvan Yan 	/*
4959*26947304SEvan Yan 	 * Allocate I/O Space for Bridge
4960*26947304SEvan Yan 	 */
4961*26947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
4962*26947304SEvan Yan 	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
4963*26947304SEvan Yan 	req.ra_boundbase = 0;
4964*26947304SEvan Yan 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
4965*26947304SEvan Yan 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
4966*26947304SEvan Yan 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
4967*26947304SEvan Yan 
4968*26947304SEvan Yan 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
4969*26947304SEvan Yan 	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
4970*26947304SEvan Yan 
4971*26947304SEvan Yan 	if (rval != NDI_SUCCESS) {
4972*26947304SEvan Yan 		if (rval == NDI_RA_PARTIAL_REQ) {
4973*26947304SEvan Yan 			/*EMPTY*/
4974*26947304SEvan Yan 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
4975*26947304SEvan Yan 		} else {
4976*26947304SEvan Yan 			DEBUG0("Failed to allocate io space for bridge\n");
4977*26947304SEvan Yan 			io_base = io_answer = io_alen = 0;
4978*26947304SEvan Yan 			/* return (PCICFG_FAILURE); */
4979*26947304SEvan Yan 		}
4980*26947304SEvan Yan 	}
4981*26947304SEvan Yan 
4982*26947304SEvan Yan 	if (io_alen) {
4983*26947304SEvan Yan 		DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
4984*26947304SEvan Yan 		    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer),
4985*26947304SEvan Yan 		    io_alen);
4986*26947304SEvan Yan 
4987*26947304SEvan Yan 		if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) ==
4988*26947304SEvan Yan 		    NDI_FAILURE) {
4989*26947304SEvan Yan 			DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
4990*26947304SEvan Yan 			return (PCICFG_FAILURE);
4991*26947304SEvan Yan 		}
4992*26947304SEvan Yan 
4993*26947304SEvan Yan 		/*
4994*26947304SEvan Yan 		 * Put available I/O into the pool.
4995*26947304SEvan Yan 		 */
4996*26947304SEvan Yan 		(void) ndi_ra_free(new_child, io_answer, io_alen,
4997*26947304SEvan Yan 		    NDI_RA_TYPE_IO, NDI_RA_PASS);
4998*26947304SEvan Yan 		io_base = io_answer;
4999*26947304SEvan Yan 	}
5000*26947304SEvan Yan 
5001*26947304SEvan Yan 	pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
5002*26947304SEvan Yan 
5003*26947304SEvan Yan 	/*
5004*26947304SEvan Yan 	 * Setup "bus-range" property before onlining the bridge.
5005*26947304SEvan Yan 	 */
5006*26947304SEvan Yan 	bus_range[0] = new_bus;
5007*26947304SEvan Yan 	bus_range[1] = max_bus;
5008*26947304SEvan Yan 
5009*26947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
5010*26947304SEvan Yan 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
5011*26947304SEvan Yan 		DEBUG0("Failed to set bus-range property");
5012*26947304SEvan Yan 		return (PCICFG_FAILURE);
5013*26947304SEvan Yan 	}
5014*26947304SEvan Yan 
5015*26947304SEvan Yan 	/*
5016*26947304SEvan Yan 	 * Reset the secondary bus
5017*26947304SEvan Yan 	 */
5018*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL,
5019*26947304SEvan Yan 	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
5020*26947304SEvan Yan 
5021*26947304SEvan Yan 	drv_usecwait(100);
5022*26947304SEvan Yan 
5023*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL,
5024*26947304SEvan Yan 	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
5025*26947304SEvan Yan 
5026*26947304SEvan Yan 	/*
5027*26947304SEvan Yan 	 * Program the memory base register with the
5028*26947304SEvan Yan 	 * start of the memory range
5029*26947304SEvan Yan 	 */
5030*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_MEM_BASE,
5031*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
5032*26947304SEvan Yan 
5033*26947304SEvan Yan 	/*
5034*26947304SEvan Yan 	 * Program the memory limit register with the
5035*26947304SEvan Yan 	 * end of the memory range.
5036*26947304SEvan Yan 	 */
5037*26947304SEvan Yan 
5038*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
5039*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(
5040*26947304SEvan Yan 	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
5041*26947304SEvan Yan 
5042*26947304SEvan Yan 	/*
5043*26947304SEvan Yan 	 * Allocate the chunk of memory (if any) not programmed into the
5044*26947304SEvan Yan 	 * bridge because of the round down.
5045*26947304SEvan Yan 	 */
5046*26947304SEvan Yan 	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
5047*26947304SEvan Yan 	    != (mem_answer + mem_alen)) {
5048*26947304SEvan Yan 		DEBUG0("Need to allocate Memory round off chunk\n");
5049*26947304SEvan Yan 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
5050*26947304SEvan Yan 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
5051*26947304SEvan Yan 		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
5052*26947304SEvan Yan 		    PCICFG_MEMGRAN);
5053*26947304SEvan Yan 		req.ra_len =  (mem_answer + mem_alen) -
5054*26947304SEvan Yan 		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
5055*26947304SEvan Yan 		    PCICFG_MEMGRAN));
5056*26947304SEvan Yan 
5057*26947304SEvan Yan 		(void) ndi_ra_alloc(new_child, &req,
5058*26947304SEvan Yan 		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
5059*26947304SEvan Yan 	}
5060*26947304SEvan Yan 
5061*26947304SEvan Yan 	/*
5062*26947304SEvan Yan 	 * Program the I/O Space Base
5063*26947304SEvan Yan 	 */
5064*26947304SEvan Yan 	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
5065*26947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(
5066*26947304SEvan Yan 	    PCICFG_LOADDR(io_answer))));
5067*26947304SEvan Yan 
5068*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
5069*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
5070*26947304SEvan Yan 
5071*26947304SEvan Yan 	/*
5072*26947304SEvan Yan 	 * Program the I/O Space Limit
5073*26947304SEvan Yan 	 */
5074*26947304SEvan Yan 	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
5075*26947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(
5076*26947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
5077*26947304SEvan Yan 	    PCICFG_IOGRAN)))) - 1);
5078*26947304SEvan Yan 
5079*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
5080*26947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(
5081*26947304SEvan Yan 	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
5082*26947304SEvan Yan 	    - 1);
5083*26947304SEvan Yan 
5084*26947304SEvan Yan 	/*
5085*26947304SEvan Yan 	 * Allocate the chunk of I/O (if any) not programmed into the
5086*26947304SEvan Yan 	 * bridge because of the round down.
5087*26947304SEvan Yan 	 */
5088*26947304SEvan Yan 	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
5089*26947304SEvan Yan 	    != (io_answer + io_alen)) {
5090*26947304SEvan Yan 		DEBUG0("Need to allocate I/O round off chunk\n");
5091*26947304SEvan Yan 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
5092*26947304SEvan Yan 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
5093*26947304SEvan Yan 		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
5094*26947304SEvan Yan 		    PCICFG_IOGRAN);
5095*26947304SEvan Yan 		req.ra_len =  (io_answer + io_alen) -
5096*26947304SEvan Yan 		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
5097*26947304SEvan Yan 		    PCICFG_IOGRAN));
5098*26947304SEvan Yan 
5099*26947304SEvan Yan 		(void) ndi_ra_alloc(new_child, &req,
5100*26947304SEvan Yan 		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
5101*26947304SEvan Yan 	}
5102*26947304SEvan Yan 
5103*26947304SEvan Yan 	/*
5104*26947304SEvan Yan 	 * Setup "ranges" property before onlining the bridge.
5105*26947304SEvan Yan 	 */
5106*26947304SEvan Yan 	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
5107*26947304SEvan Yan 
5108*26947304SEvan Yan 	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
5109*26947304SEvan Yan 	range[0].child_lo = range[0].parent_lo = io_base;
5110*26947304SEvan Yan 	range[1].child_hi = range[1].parent_hi |=
5111*26947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
5112*26947304SEvan Yan 	range[1].child_lo = range[1].parent_lo = mem_base;
5113*26947304SEvan Yan 
5114*26947304SEvan Yan 	range[0].size_lo = io_alen;
5115*26947304SEvan Yan 	if (pcicfg_update_ranges_prop(new_child, &range[0])) {
5116*26947304SEvan Yan 		DEBUG0("Failed to update ranges (io)\n");
5117*26947304SEvan Yan 		return (PCICFG_FAILURE);
5118*26947304SEvan Yan 	}
5119*26947304SEvan Yan 	range[1].size_lo = mem_alen;
5120*26947304SEvan Yan 	if (pcicfg_update_ranges_prop(new_child, &range[1])) {
5121*26947304SEvan Yan 		DEBUG0("Failed to update ranges (memory)\n");
5122*26947304SEvan Yan 		return (PCICFG_FAILURE);
5123*26947304SEvan Yan 	}
5124*26947304SEvan Yan 
5125*26947304SEvan Yan 	/*
5126*26947304SEvan Yan 	 * Clear status bits
5127*26947304SEvan Yan 	 */
5128*26947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
5129*26947304SEvan Yan 
5130*26947304SEvan Yan 	/*
5131*26947304SEvan Yan 	 * Turn off prefetchable range
5132*26947304SEvan Yan 	 */
5133*26947304SEvan Yan 	pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
5134*26947304SEvan Yan 	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
5135*26947304SEvan Yan 	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
5136*26947304SEvan Yan 
5137*26947304SEvan Yan 	/*
5138*26947304SEvan Yan 	 * Needs to be set to this value
5139*26947304SEvan Yan 	 */
5140*26947304SEvan Yan 	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
5141*26947304SEvan Yan 
5142*26947304SEvan Yan 	/* check our device_type as defined by Open Firmware */
5143*26947304SEvan Yan 	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
5144*26947304SEvan Yan 		pcie_device_type = 1;
5145*26947304SEvan Yan 
5146*26947304SEvan Yan 	/*
5147*26947304SEvan Yan 	 * Set bus properties
5148*26947304SEvan Yan 	 */
5149*26947304SEvan Yan 	if (pcicfg_set_busnode_props(new_child, pcie_device_type,
5150*26947304SEvan Yan 	    (int)bus, (int)new_bus) != PCICFG_SUCCESS) {
5151*26947304SEvan Yan 		DEBUG0("Failed to set busnode props\n");
5152*26947304SEvan Yan 		return (PCICFG_FAILURE);
5153*26947304SEvan Yan 	}
5154*26947304SEvan Yan 
5155*26947304SEvan Yan 	(void) pcicfg_device_on(h);
5156*26947304SEvan Yan 
5157*26947304SEvan Yan 	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
5158*26947304SEvan Yan 	    != NDI_SUCCESS) {
5159*26947304SEvan Yan 		DEBUG0("Unable to online bridge\n");
5160*26947304SEvan Yan 		return (PCICFG_FAILURE);
5161*26947304SEvan Yan 	}
5162*26947304SEvan Yan 
5163*26947304SEvan Yan 	DEBUG0("Bridge is ONLINE\n");
5164*26947304SEvan Yan 
5165*26947304SEvan Yan 	/*
5166*26947304SEvan Yan 	 * After a Reset, we need to wait 2^25 clock cycles before the
5167*26947304SEvan Yan 	 * first Configuration access.  The worst case is 33MHz, which
5168*26947304SEvan Yan 	 * is a 1 second wait.
5169*26947304SEvan Yan 	 */
5170*26947304SEvan Yan 	drv_usecwait(pcicfg_sec_reset_delay);
5171*26947304SEvan Yan 
5172*26947304SEvan Yan 	/*
5173*26947304SEvan Yan 	 * Probe all children devices
5174*26947304SEvan Yan 	 */
5175*26947304SEvan Yan 	DEBUG0("Bridge Programming Complete - probe children\n");
5176*26947304SEvan Yan 	ndi_devi_enter(new_child, &count);
5177*26947304SEvan Yan 	for (i = 0; ((i < PCICFG_MAX_DEVICE) && (ari_mode == B_FALSE));
5178*26947304SEvan Yan 	    i++) {
5179*26947304SEvan Yan 		for (j = 0; j < max_function; ) {
5180*26947304SEvan Yan 			if (ari_mode)
5181*26947304SEvan Yan 				trans_device = j >> 3;
5182*26947304SEvan Yan 			else
5183*26947304SEvan Yan 				trans_device = i;
5184*26947304SEvan Yan 
5185*26947304SEvan Yan 			if ((rval = pcicfg_fcode_probe(new_child,
5186*26947304SEvan Yan 			    new_bus, trans_device, (j & 7), highest_bus, 0))
5187*26947304SEvan Yan 			    != PCICFG_SUCCESS) {
5188*26947304SEvan Yan 				if (rval == PCICFG_NODEVICE) {
5189*26947304SEvan Yan 					DEBUG3("No Device at bus [0x%x]"
5190*26947304SEvan Yan 					    "device [0x%x] "
5191*26947304SEvan Yan 					    "func [0x%x]\n", new_bus,
5192*26947304SEvan Yan 					    trans_device, j & 7);
5193*26947304SEvan Yan 
5194*26947304SEvan Yan 					if (j)
5195*26947304SEvan Yan 						goto next;
5196*26947304SEvan Yan 				} else {
5197*26947304SEvan Yan 					DEBUG3("Failed to configure bus "
5198*26947304SEvan Yan 					    "[0x%x] device [0x%x] "
5199*26947304SEvan Yan 					    "func [0x%x]\n", new_bus,
5200*26947304SEvan Yan 					    trans_device, j & 7);
5201*26947304SEvan Yan 
5202*26947304SEvan Yan 					rval = PCICFG_FAILURE;
5203*26947304SEvan Yan 				}
5204*26947304SEvan Yan 				break;
5205*26947304SEvan Yan 			}
5206*26947304SEvan Yan next:
5207*26947304SEvan Yan 			new_device = pcicfg_devi_find(new_child,
5208*26947304SEvan Yan 			    trans_device, (j & 7));
5209*26947304SEvan Yan 
5210*26947304SEvan Yan 			/*
5211*26947304SEvan Yan 			 * Determine if ARI Forwarding should be enabled.
5212*26947304SEvan Yan 			 */
5213*26947304SEvan Yan 			if (j == 0) {
5214*26947304SEvan Yan 				if (new_device == NULL)
5215*26947304SEvan Yan 					break;
5216*26947304SEvan Yan 
5217*26947304SEvan Yan 				if ((pcie_ari_supported(new_child) ==
5218*26947304SEvan Yan 				    PCIE_ARI_FORW_ENABLED) &&
5219*26947304SEvan Yan 				    (pcie_ari_device(new_device) ==
5220*26947304SEvan Yan 				    PCIE_ARI_DEVICE)) {
5221*26947304SEvan Yan 					if (pcie_ari_enable(new_child) ==
5222*26947304SEvan Yan 					    DDI_SUCCESS) {
5223*26947304SEvan Yan 						(void) ddi_prop_create(
5224*26947304SEvan Yan 						    DDI_DEV_T_NONE,
5225*26947304SEvan Yan 						    new_child,
5226*26947304SEvan Yan 						    DDI_PROP_CANSLEEP,
5227*26947304SEvan Yan 						    "ari-enabled", NULL, 0);
5228*26947304SEvan Yan 						ari_mode = B_TRUE;
5229*26947304SEvan Yan 						max_function =
5230*26947304SEvan Yan 						    PCICFG_MAX_ARI_FUNCTION;
5231*26947304SEvan Yan 					}
5232*26947304SEvan Yan 				}
5233*26947304SEvan Yan 			}
5234*26947304SEvan Yan 
5235*26947304SEvan Yan 			if (ari_mode == B_TRUE) {
5236*26947304SEvan Yan 				int next_function;
5237*26947304SEvan Yan 
5238*26947304SEvan Yan 				if (new_device == NULL)
5239*26947304SEvan Yan 					break;
5240*26947304SEvan Yan 
5241*26947304SEvan Yan 				if (pcie_ari_get_next_function(new_device,
5242*26947304SEvan Yan 				    &next_function) != DDI_SUCCESS)
5243*26947304SEvan Yan 					break;
5244*26947304SEvan Yan 
5245*26947304SEvan Yan 				j = next_function;
5246*26947304SEvan Yan 
5247*26947304SEvan Yan 				if (next_function == 0)
5248*26947304SEvan Yan 					break;
5249*26947304SEvan Yan 			} else
5250*26947304SEvan Yan 				j++;
5251*26947304SEvan Yan 		}
5252*26947304SEvan Yan 	}
5253*26947304SEvan Yan 
5254*26947304SEvan Yan 	ndi_devi_exit(new_child, count);
5255*26947304SEvan Yan 
5256*26947304SEvan Yan 	/* if empty topology underneath, it is still a success. */
5257*26947304SEvan Yan 	if (rval != PCICFG_FAILURE)
5258*26947304SEvan Yan 		rval = PCICFG_SUCCESS;
5259*26947304SEvan Yan 
5260*26947304SEvan Yan 	/*
5261*26947304SEvan Yan 	 * Offline the bridge to allow reprogramming of resources.
5262*26947304SEvan Yan 	 *
5263*26947304SEvan Yan 	 * This should always succeed since nobody else has started to
5264*26947304SEvan Yan 	 * use it yet, failing to detach the driver would indicate a bug.
5265*26947304SEvan Yan 	 * Also in that case it's better just panic than allowing the
5266*26947304SEvan Yan 	 * configurator to proceed with BAR reprogramming without bridge
5267*26947304SEvan Yan 	 * driver detached.
5268*26947304SEvan Yan 	 */
5269*26947304SEvan Yan 	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
5270*26947304SEvan Yan 	    == NDI_SUCCESS);
5271*26947304SEvan Yan 
5272*26947304SEvan Yan 	phdl.dip = new_child;
5273*26947304SEvan Yan 	phdl.memory_base = mem_answer;
5274*26947304SEvan Yan 	phdl.io_base = (uint32_t)io_answer;
5275*26947304SEvan Yan 	phdl.error = PCICFG_SUCCESS;    /* in case of empty child tree */
5276*26947304SEvan Yan 
5277*26947304SEvan Yan 	ndi_devi_enter(ddi_get_parent(new_child), &count);
5278*26947304SEvan Yan 	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
5279*26947304SEvan Yan 	ndi_devi_exit(ddi_get_parent(new_child), count);
5280*26947304SEvan Yan 
5281*26947304SEvan Yan 	if (phdl.error != PCICFG_SUCCESS) {
5282*26947304SEvan Yan 		DEBUG0("Failure summing resources\n");
5283*26947304SEvan Yan 		return (PCICFG_FAILURE);
5284*26947304SEvan Yan 	}
5285*26947304SEvan Yan 
5286*26947304SEvan Yan 	num_slots = pcicfg_get_nslots(new_child, h);
5287*26947304SEvan Yan 	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
5288*26947304SEvan Yan 	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
5289*26947304SEvan Yan 
5290*26947304SEvan Yan 	DEBUG3("Start of Unallocated Bridge(%d slots) Resources "
5291*26947304SEvan Yan 	    "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end);
5292*26947304SEvan Yan 
5293*26947304SEvan Yan 	/*
5294*26947304SEvan Yan 	 * Before probing the children we've allocated maximum MEM/IO
5295*26947304SEvan Yan 	 * resources from parent, and updated "available" property
5296*26947304SEvan Yan 	 * accordingly. Later we'll be giving up unused resources to
5297*26947304SEvan Yan 	 * the parent, thus we need to destroy "available" property
5298*26947304SEvan Yan 	 * here otherwise it will be out-of-sync with the actual free
5299*26947304SEvan Yan 	 * resources this bridge has. This property will be rebuilt below
5300*26947304SEvan Yan 	 * with the actual free resources reserved for hotplug slots
5301*26947304SEvan Yan 	 * (if any).
5302*26947304SEvan Yan 	 */
5303*26947304SEvan Yan 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
5304*26947304SEvan Yan 	/*
5305*26947304SEvan Yan 	 * if the bridge a slots, then preallocate. If not, assume static
5306*26947304SEvan Yan 	 * configuration. Also check for preallocation limits and spit
5307*26947304SEvan Yan 	 * warning messages appropriately (perhaps some can be in debug mode).
5308*26947304SEvan Yan 	 */
5309*26947304SEvan Yan 	if (num_slots) {
5310*26947304SEvan Yan 		pci_regspec_t reg;
5311*26947304SEvan Yan 		uint64_t mem_assigned = mem_end;
5312*26947304SEvan Yan 		uint64_t io_assigned = io_end;
5313*26947304SEvan Yan 		uint64_t mem_reqd = mem_answer + (num_slots *
5314*26947304SEvan Yan 		    pcicfg_slot_memsize);
5315*26947304SEvan Yan 		uint64_t io_reqd = io_answer + (num_slots *
5316*26947304SEvan Yan 		    pcicfg_slot_iosize);
5317*26947304SEvan Yan 		uint8_t highest_bus_reqd = new_bus + (num_slots *
5318*26947304SEvan Yan 		    pcicfg_slot_busnums);
5319*26947304SEvan Yan #ifdef DEBUG
5320*26947304SEvan Yan 		if (mem_end > mem_reqd)
5321*26947304SEvan Yan 			DEBUG3("Memory space consumed by bridge"
5322*26947304SEvan Yan 			    " more than planned for %d slot(s)(%lx, %lx)",
5323*26947304SEvan Yan 			    num_slots, mem_answer, mem_end);
5324*26947304SEvan Yan 		if (io_end > io_reqd)
5325*26947304SEvan Yan 			DEBUG3("IO space consumed by bridge"
5326*26947304SEvan Yan 			    " more than planned for %d slot(s)(%lx, %lx)",
5327*26947304SEvan Yan 			    num_slots, io_answer, io_end);
5328*26947304SEvan Yan 		if (*highest_bus > highest_bus_reqd)
5329*26947304SEvan Yan 			DEBUG3("Buses consumed by bridge"
5330*26947304SEvan Yan 			    " more than planned for %d slot(s)(%x, %x)",
5331*26947304SEvan Yan 			    num_slots, new_bus, *highest_bus);
5332*26947304SEvan Yan 
5333*26947304SEvan Yan 		if (mem_reqd > (mem_answer + mem_alen))
5334*26947304SEvan Yan 			DEBUG3("Memory space required by bridge"
5335*26947304SEvan Yan 			    " more than available for %d slot(s)(%lx, %lx)",
5336*26947304SEvan Yan 			    num_slots, mem_answer, mem_end);
5337*26947304SEvan Yan 
5338*26947304SEvan Yan 		if (io_reqd > (io_answer + io_alen))
5339*26947304SEvan Yan 			DEBUG3("IO space required by bridge"
5340*26947304SEvan Yan 			    " more than available for %d slot(s)(%lx, %lx)",
5341*26947304SEvan Yan 			    num_slots, io_answer, io_end);
5342*26947304SEvan Yan 		if (highest_bus_reqd > max_bus)
5343*26947304SEvan Yan 			DEBUG3("Bus numbers required by bridge"
5344*26947304SEvan Yan 			    " more than available for %d slot(s)(%x, %x)",
5345*26947304SEvan Yan 			    num_slots, new_bus, *highest_bus);
5346*26947304SEvan Yan #endif
5347*26947304SEvan Yan 		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
5348*26947304SEvan Yan 		    mem_end);
5349*26947304SEvan Yan 		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
5350*26947304SEvan Yan 		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
5351*26947304SEvan Yan 		    *highest_bus);
5352*26947304SEvan Yan 		DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n",
5353*26947304SEvan Yan 		    mem_end, io_end, *highest_bus);
5354*26947304SEvan Yan 
5355*26947304SEvan Yan 		mem_size = mem_end - mem_assigned;
5356*26947304SEvan Yan 		io_size = io_end - io_assigned;
5357*26947304SEvan Yan 
5358*26947304SEvan Yan 		reg.pci_phys_mid = reg.pci_size_hi = 0;
5359*26947304SEvan Yan 		if (io_size > 0) {
5360*26947304SEvan Yan 			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO);
5361*26947304SEvan Yan 			reg.pci_phys_low = io_assigned;
5362*26947304SEvan Yan 			reg.pci_size_low = io_size;
5363*26947304SEvan Yan 			if (pcicfg_update_available_prop(new_child, &reg)) {
5364*26947304SEvan Yan 				DEBUG0("Failed to update available prop "
5365*26947304SEvan Yan 				    "(io)\n");
5366*26947304SEvan Yan 				return (PCICFG_FAILURE);
5367*26947304SEvan Yan 			}
5368*26947304SEvan Yan 		}
5369*26947304SEvan Yan 		if (mem_size > 0) {
5370*26947304SEvan Yan 			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32);
5371*26947304SEvan Yan 			reg.pci_phys_low = mem_assigned;
5372*26947304SEvan Yan 			reg.pci_size_low = mem_size;
5373*26947304SEvan Yan 			if (pcicfg_update_available_prop(new_child, &reg)) {
5374*26947304SEvan Yan 				DEBUG0("Failed to update available prop "
5375*26947304SEvan Yan 				    "(memory)\n");
5376*26947304SEvan Yan 				return (PCICFG_FAILURE);
5377*26947304SEvan Yan 			}
5378*26947304SEvan Yan 		}
5379*26947304SEvan Yan 	}
5380*26947304SEvan Yan 
5381*26947304SEvan Yan 	/*
5382*26947304SEvan Yan 	 * Give back unused memory space to parent.
5383*26947304SEvan Yan 	 */
5384*26947304SEvan Yan 	(void) ndi_ra_free(ddi_get_parent(new_child),
5385*26947304SEvan Yan 	    mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
5386*26947304SEvan Yan 	    NDI_RA_PASS);
5387*26947304SEvan Yan 
5388*26947304SEvan Yan 	if (mem_end == mem_answer) {
5389*26947304SEvan Yan 		DEBUG0("No memory resources used\n");
5390*26947304SEvan Yan 		/*
5391*26947304SEvan Yan 		 * To prevent the bridge from forwarding any Memory
5392*26947304SEvan Yan 		 * transactions, the Memory Limit will be programmed
5393*26947304SEvan Yan 		 * with a smaller value than the Memory Base.
5394*26947304SEvan Yan 		 */
5395*26947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
5396*26947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
5397*26947304SEvan Yan 
5398*26947304SEvan Yan 		mem_size = 0;
5399*26947304SEvan Yan 	} else {
5400*26947304SEvan Yan 		/*
5401*26947304SEvan Yan 		 * Reprogram the end of the memory.
5402*26947304SEvan Yan 		 */
5403*26947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
5404*26947304SEvan Yan 		    PCICFG_HIWORD(mem_end) - 1);
5405*26947304SEvan Yan 		mem_size = mem_end - mem_base;
5406*26947304SEvan Yan 	}
5407*26947304SEvan Yan 
5408*26947304SEvan Yan 	/*
5409*26947304SEvan Yan 	 * Give back unused io space to parent.
5410*26947304SEvan Yan 	 */
5411*26947304SEvan Yan 	(void) ndi_ra_free(ddi_get_parent(new_child),
5412*26947304SEvan Yan 	    io_end, (io_answer + io_alen) - io_end,
5413*26947304SEvan Yan 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
5414*26947304SEvan Yan 
5415*26947304SEvan Yan 	if (io_end == io_answer) {
5416*26947304SEvan Yan 		DEBUG0("No IO Space resources used\n");
5417*26947304SEvan Yan 
5418*26947304SEvan Yan 		/*
5419*26947304SEvan Yan 		 * To prevent the bridge from forwarding any I/O
5420*26947304SEvan Yan 		 * transactions, the I/O Limit will be programmed
5421*26947304SEvan Yan 		 * with a smaller value than the I/O Base.
5422*26947304SEvan Yan 		 */
5423*26947304SEvan Yan 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
5424*26947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
5425*26947304SEvan Yan 		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
5426*26947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
5427*26947304SEvan Yan 
5428*26947304SEvan Yan 		io_size = 0;
5429*26947304SEvan Yan 	} else {
5430*26947304SEvan Yan 		/*
5431*26947304SEvan Yan 		 * Reprogram the end of the io space.
5432*26947304SEvan Yan 		 */
5433*26947304SEvan Yan 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
5434*26947304SEvan Yan 		    PCICFG_HIBYTE(PCICFG_LOWORD(
5435*26947304SEvan Yan 		    PCICFG_LOADDR(io_end) - 1)));
5436*26947304SEvan Yan 
5437*26947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
5438*26947304SEvan Yan 		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
5439*26947304SEvan Yan 
5440*26947304SEvan Yan 		io_size = io_end - io_base;
5441*26947304SEvan Yan 	}
5442*26947304SEvan Yan 
5443*26947304SEvan Yan 	if ((max_bus - *highest_bus) > 0) {
5444*26947304SEvan Yan 		/*
5445*26947304SEvan Yan 		 * Give back unused bus numbers
5446*26947304SEvan Yan 		 */
5447*26947304SEvan Yan 		(void) ndi_ra_free(ddi_get_parent(new_child),
5448*26947304SEvan Yan 		    *highest_bus+1, max_bus - *highest_bus,
5449*26947304SEvan Yan 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
5450*26947304SEvan Yan 	}
5451*26947304SEvan Yan 
5452*26947304SEvan Yan 	/*
5453*26947304SEvan Yan 	 * Set bus numbers to ranges encountered during scan
5454*26947304SEvan Yan 	 */
5455*26947304SEvan Yan 	pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
5456*26947304SEvan Yan 
5457*26947304SEvan Yan 	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
5458*26947304SEvan Yan 	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
5459*26947304SEvan Yan 	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
5460*26947304SEvan Yan 	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
5461*26947304SEvan Yan 
5462*26947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
5463*26947304SEvan Yan 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
5464*26947304SEvan Yan 		DEBUG0("Failed to set bus-range property");
5465*26947304SEvan Yan 		return (PCICFG_FAILURE);
5466*26947304SEvan Yan 	}
5467*26947304SEvan Yan 
5468*26947304SEvan Yan 	/*
5469*26947304SEvan Yan 	 * Remove the ranges property if it exists since we will create
5470*26947304SEvan Yan 	 * a new one.
5471*26947304SEvan Yan 	 */
5472*26947304SEvan Yan 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
5473*26947304SEvan Yan 
5474*26947304SEvan Yan 	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
5475*26947304SEvan Yan 	    mem_base, mem_size);
5476*26947304SEvan Yan 	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
5477*26947304SEvan Yan 	    io_base, io_size);
5478*26947304SEvan Yan 
5479*26947304SEvan Yan 	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
5480*26947304SEvan Yan 
5481*26947304SEvan Yan 	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
5482*26947304SEvan Yan 	range[0].child_lo = range[0].parent_lo = io_base;
5483*26947304SEvan Yan 	range[1].child_hi = range[1].parent_hi |=
5484*26947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
5485*26947304SEvan Yan 	range[1].child_lo = range[1].parent_lo = mem_base;
5486*26947304SEvan Yan 
5487*26947304SEvan Yan 	if (io_size > 0) {
5488*26947304SEvan Yan 		range[0].size_lo = io_size;
5489*26947304SEvan Yan 		if (pcicfg_update_ranges_prop(new_child, &range[0])) {
5490*26947304SEvan Yan 			DEBUG0("Failed to update ranges (io)\n");
5491*26947304SEvan Yan 			return (PCICFG_FAILURE);
5492*26947304SEvan Yan 		}
5493*26947304SEvan Yan 	}
5494*26947304SEvan Yan 	if (mem_size > 0) {
5495*26947304SEvan Yan 		range[1].size_lo = mem_size;
5496*26947304SEvan Yan 		if (pcicfg_update_ranges_prop(new_child, &range[1])) {
5497*26947304SEvan Yan 			DEBUG0("Failed to update ranges (memory)\n");
5498*26947304SEvan Yan 			return (PCICFG_FAILURE);
5499*26947304SEvan Yan 		}
5500*26947304SEvan Yan 	}
5501*26947304SEvan Yan 
5502*26947304SEvan Yan 	/*
5503*26947304SEvan Yan 	 * Remove the resource maps for the bridge since we no longer
5504*26947304SEvan Yan 	 * need them.  Note that the failure is ignored since the
5505*26947304SEvan Yan 	 * ndi_devi_offline above may have already taken care of it via
5506*26947304SEvan Yan 	 * driver detach.
5507*26947304SEvan Yan 	 * It has been checked that there are no other reasons for
5508*26947304SEvan Yan 	 * failure other than map itself being non-existent. So we are Ok.
5509*26947304SEvan Yan 	 */
5510*26947304SEvan Yan 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
5511*26947304SEvan Yan 		/*EMPTY*/
5512*26947304SEvan Yan 		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n");
5513*26947304SEvan Yan 	}
5514*26947304SEvan Yan 
5515*26947304SEvan Yan 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
5516*26947304SEvan Yan 		/*EMPTY*/
5517*26947304SEvan Yan 		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n");
5518*26947304SEvan Yan 	}
5519*26947304SEvan Yan 
5520*26947304SEvan Yan 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM)
5521*26947304SEvan Yan 	    == NDI_FAILURE) {
5522*26947304SEvan Yan 		/*EMPTY*/
5523*26947304SEvan Yan 		DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
5524*26947304SEvan Yan 	}
5525*26947304SEvan Yan 
5526*26947304SEvan Yan 	return (rval);
5527*26947304SEvan Yan }
5528*26947304SEvan Yan 
5529*26947304SEvan Yan /*
5530*26947304SEvan Yan  * Return PCICFG_SUCCESS if device exists at the specified address.
5531*26947304SEvan Yan  * Return PCICFG_NODEVICE is no device exists at the specified address.
5532*26947304SEvan Yan  *
5533*26947304SEvan Yan  */
5534*26947304SEvan Yan int
5535*26947304SEvan Yan pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
5536*26947304SEvan Yan {
5537*26947304SEvan Yan 	caddr_t			virt;
5538*26947304SEvan Yan 	ddi_device_acc_attr_t	attr;
5539*26947304SEvan Yan 	int			status;
5540*26947304SEvan Yan 	int			rlen;
5541*26947304SEvan Yan 	pci_regspec_t		*reg;
5542*26947304SEvan Yan 	int			ret = DDI_SUCCESS;
5543*26947304SEvan Yan 	int16_t			tmp;
5544*26947304SEvan Yan 	/*
5545*26947304SEvan Yan 	 * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly
5546*26947304SEvan Yan 	 * mapped, otherwise it is 0. "flags" is introduced in support of any
5547*26947304SEvan Yan 	 * non transparent bridges, where configuration space is indirectly
5548*26947304SEvan Yan 	 * mapped.
5549*26947304SEvan Yan 	 * Indirect mapping is always true on sun4v systems.
5550*26947304SEvan Yan 	 */
5551*26947304SEvan Yan 	int			flags = 0;
5552*26947304SEvan Yan 
5553*26947304SEvan Yan 
5554*26947304SEvan Yan 	/*
5555*26947304SEvan Yan 	 * Get the pci register spec from the node
5556*26947304SEvan Yan 	 */
5557*26947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
5558*26947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
5559*26947304SEvan Yan 
5560*26947304SEvan Yan 	switch (status) {
5561*26947304SEvan Yan 		case DDI_PROP_SUCCESS:
5562*26947304SEvan Yan 		break;
5563*26947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
5564*26947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
5565*26947304SEvan Yan 			return (PCICFG_FAILURE);
5566*26947304SEvan Yan 		default:
5567*26947304SEvan Yan 			DEBUG0("no reg property\n");
5568*26947304SEvan Yan 			return (PCICFG_FAILURE);
5569*26947304SEvan Yan 	}
5570*26947304SEvan Yan 
5571*26947304SEvan Yan 	if (pcicfg_indirect_map(dip) == DDI_SUCCESS)
5572*26947304SEvan Yan 		flags |= PCICFG_CONF_INDIRECT_MAP;
5573*26947304SEvan Yan 
5574*26947304SEvan Yan 	/*
5575*26947304SEvan Yan 	 * Map in configuration space (temporarily)
5576*26947304SEvan Yan 	 */
5577*26947304SEvan Yan 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5578*26947304SEvan Yan 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
5579*26947304SEvan Yan 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5580*26947304SEvan Yan 	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
5581*26947304SEvan Yan 
5582*26947304SEvan Yan #ifdef	EFCODE21554
5583*26947304SEvan Yan 	if (ddi_regs_map_setup(dip, 0, &virt,
5584*26947304SEvan Yan 	    0, 0, &attr, handle) != DDI_SUCCESS)
5585*26947304SEvan Yan #else
5586*26947304SEvan Yan 	if (pcicfg_map_phys(dip, reg, &virt, &attr, handle)
5587*26947304SEvan Yan 	    != DDI_SUCCESS)
5588*26947304SEvan Yan #endif
5589*26947304SEvan Yan 	{
5590*26947304SEvan Yan 		DEBUG0("pcicfg_config_setup():"
5591*26947304SEvan Yan 		"Failed to setup config space\n");
5592*26947304SEvan Yan 
5593*26947304SEvan Yan 		kmem_free((caddr_t)reg, rlen);
5594*26947304SEvan Yan 		return (PCICFG_FAILURE);
5595*26947304SEvan Yan 	}
5596*26947304SEvan Yan 
5597*26947304SEvan Yan 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
5598*26947304SEvan Yan 		/*
5599*26947304SEvan Yan 		 * need to use DDI interfaces as the conf space is
5600*26947304SEvan Yan 		 * cannot be directly accessed by the host.
5601*26947304SEvan Yan 		 */
5602*26947304SEvan Yan 		tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt);
5603*26947304SEvan Yan 	} else {
5604*26947304SEvan Yan 		ret = ddi_peek16(dip, (int16_t *)virt, &tmp);
5605*26947304SEvan Yan 	}
5606*26947304SEvan Yan 
5607*26947304SEvan Yan 	if (ret == DDI_SUCCESS) {
5608*26947304SEvan Yan 		if (tmp == -1) {
5609*26947304SEvan Yan 			DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
5610*26947304SEvan Yan 			ret = PCICFG_NODEVICE;
5611*26947304SEvan Yan 		} else {
5612*26947304SEvan Yan 			/* XXX - Need to check why HV is returning 0 */
5613*26947304SEvan Yan 			if (tmp == 0) {
5614*26947304SEvan Yan 				DEBUG0("Device Not Ready yet ?");
5615*26947304SEvan Yan 				ret = PCICFG_NODEVICE;
5616*26947304SEvan Yan 			} else {
5617*26947304SEvan Yan 				DEBUG1("DEVICEFOUND, read %x\n", tmp);
5618*26947304SEvan Yan 				ret = PCICFG_SUCCESS;
5619*26947304SEvan Yan 			}
5620*26947304SEvan Yan 		}
5621*26947304SEvan Yan 	} else {
5622*26947304SEvan Yan 		DEBUG0("ddi_peek failed, must be NODEVICE\n");
5623*26947304SEvan Yan 		ret = PCICFG_NODEVICE;
5624*26947304SEvan Yan 	}
5625*26947304SEvan Yan 
5626*26947304SEvan Yan 	/*
5627*26947304SEvan Yan 	 * A bug in XMITS 3.0 causes us to miss the Master Abort Split
5628*26947304SEvan Yan 	 * Completion message.  The result is the error message being
5629*26947304SEvan Yan 	 * sent back as part of the config data.  If the first two words
5630*26947304SEvan Yan 	 * of the config space happen to be the same as the Master Abort
5631*26947304SEvan Yan 	 * message, then report back that there is no device there.
5632*26947304SEvan Yan 	 */
5633*26947304SEvan Yan 	if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) {
5634*26947304SEvan Yan 		int32_t	pcix_scm;
5635*26947304SEvan Yan 
5636*26947304SEvan Yan #define		PCICFG_PCIX_SCM	0x10000004
5637*26947304SEvan Yan 
5638*26947304SEvan Yan 		pcix_scm = 0;
5639*26947304SEvan Yan 		(void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm);
5640*26947304SEvan Yan 		if (pcix_scm == PCICFG_PCIX_SCM) {
5641*26947304SEvan Yan 			pcix_scm = 0;
5642*26947304SEvan Yan 			(void) ddi_peek32(dip,
5643*26947304SEvan Yan 			    (int32_t *)(virt + 4), &pcix_scm);
5644*26947304SEvan Yan 			if (pcix_scm == PCICFG_PCIX_SCM)
5645*26947304SEvan Yan 				ret = PCICFG_NODEVICE;
5646*26947304SEvan Yan 		}
5647*26947304SEvan Yan 	}
5648*26947304SEvan Yan 
5649*26947304SEvan Yan 	if (ret == PCICFG_NODEVICE)
5650*26947304SEvan Yan #ifdef	EFCODE21554
5651*26947304SEvan Yan 		ddi_regs_map_free(handle);
5652*26947304SEvan Yan #else
5653*26947304SEvan Yan 		pcicfg_unmap_phys(handle, reg);
5654*26947304SEvan Yan #endif
5655*26947304SEvan Yan 
5656*26947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
5657*26947304SEvan Yan 
5658*26947304SEvan Yan 	return (ret);
5659*26947304SEvan Yan 
5660*26947304SEvan Yan }
5661*26947304SEvan Yan 
5662*26947304SEvan Yan static void
5663*26947304SEvan Yan pcicfg_config_teardown(ddi_acc_handle_t *handle)
5664*26947304SEvan Yan {
5665*26947304SEvan Yan 	(void) ddi_regs_map_free(handle);
5666*26947304SEvan Yan }
5667*26947304SEvan Yan 
5668*26947304SEvan Yan static int
5669*26947304SEvan Yan pcicfg_add_config_reg(dev_info_t *dip,
5670*26947304SEvan Yan 	uint_t bus, uint_t device, uint_t func)
5671*26947304SEvan Yan {
5672*26947304SEvan Yan 	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
5673*26947304SEvan Yan 
5674*26947304SEvan Yan 	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
5675*26947304SEvan Yan 
5676*26947304SEvan Yan 	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
5677*26947304SEvan Yan 	    "reg", reg, 5));
5678*26947304SEvan Yan }
5679*26947304SEvan Yan 
5680*26947304SEvan Yan static int
5681*26947304SEvan Yan pcicfg_dump_assigned(dev_info_t *dip)
5682*26947304SEvan Yan {
5683*26947304SEvan Yan 	pci_regspec_t		*reg;
5684*26947304SEvan Yan 	int			length;
5685*26947304SEvan Yan 	int			rcount;
5686*26947304SEvan Yan 	int			i;
5687*26947304SEvan Yan 
5688*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
5689*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&reg,
5690*26947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
5691*26947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
5692*26947304SEvan Yan 		return (PCICFG_FAILURE);
5693*26947304SEvan Yan 	}
5694*26947304SEvan Yan 
5695*26947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
5696*26947304SEvan Yan 	for (i = 0; i < rcount; i++) {
5697*26947304SEvan Yan 		DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n",
5698*26947304SEvan Yan 		    reg[i].pci_size_low, reg[i].pci_phys_low,
5699*26947304SEvan Yan 		    reg[i].pci_phys_mid, reg[i].pci_phys_hi);
5700*26947304SEvan Yan 	}
5701*26947304SEvan Yan 	/*
5702*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
5703*26947304SEvan Yan 	 */
5704*26947304SEvan Yan 	kmem_free((caddr_t)reg, length);
5705*26947304SEvan Yan 
5706*26947304SEvan Yan 	return (PCICFG_SUCCESS);
5707*26947304SEvan Yan }
5708*26947304SEvan Yan 
5709*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
5710*26947304SEvan Yan static int
5711*26947304SEvan Yan pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func,
5712*26947304SEvan Yan     uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr,
5713*26947304SEvan Yan     int *fcode_size, int rom_paddr, int rom_size)
5714*26947304SEvan Yan {
5715*26947304SEvan Yan 	pci_regspec_t		p;
5716*26947304SEvan Yan 	int			pci_data;
5717*26947304SEvan Yan 	int			start_of_fcode;
5718*26947304SEvan Yan 	int			image_length;
5719*26947304SEvan Yan 	int			code_type;
5720*26947304SEvan Yan 	ddi_acc_handle_t	h;
5721*26947304SEvan Yan 	ddi_device_acc_attr_t	acc;
5722*26947304SEvan Yan 	uint8_t			*addr;
5723*26947304SEvan Yan 	int8_t			image_not_found, indicator;
5724*26947304SEvan Yan 	uint16_t		vendor_id_img, device_id_img;
5725*26947304SEvan Yan 	int16_t			rom_sig;
5726*26947304SEvan Yan #ifdef DEBUG
5727*26947304SEvan Yan 	int i;
5728*26947304SEvan Yan #endif
5729*26947304SEvan Yan 
5730*26947304SEvan Yan 	DEBUG4("pcicfg_load_fcode() - "
5731*26947304SEvan Yan 	    "bus %x device =%x func=%x rom_paddr=%lx\n",
5732*26947304SEvan Yan 	    bus, device, func, rom_paddr);
5733*26947304SEvan Yan 	DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n",
5734*26947304SEvan Yan 	    vendor_id, device_id);
5735*26947304SEvan Yan 
5736*26947304SEvan Yan 	*fcode_size = 0;
5737*26947304SEvan Yan 	*fcode_addr = NULL;
5738*26947304SEvan Yan 
5739*26947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5740*26947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
5741*26947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5742*26947304SEvan Yan 
5743*26947304SEvan Yan 	p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device,
5744*26947304SEvan Yan 	    func, PCI_CONF_ROM);
5745*26947304SEvan Yan 
5746*26947304SEvan Yan 	p.pci_phys_mid = 0;
5747*26947304SEvan Yan 	p.pci_phys_low = 0;
5748*26947304SEvan Yan 
5749*26947304SEvan Yan 	p.pci_size_low = rom_size;
5750*26947304SEvan Yan 	p.pci_size_hi = 0;
5751*26947304SEvan Yan 
5752*26947304SEvan Yan 	if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) {
5753*26947304SEvan Yan 		DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low);
5754*26947304SEvan Yan 		return (PCICFG_FAILURE);
5755*26947304SEvan Yan 	}
5756*26947304SEvan Yan 
5757*26947304SEvan Yan 	/*
5758*26947304SEvan Yan 	 * Walk the ROM to find the proper image for this device.
5759*26947304SEvan Yan 	 */
5760*26947304SEvan Yan 	image_not_found = 1;
5761*26947304SEvan Yan 	while (image_not_found) {
5762*26947304SEvan Yan 		DEBUG1("Expansion ROM maps to %lx\n", addr);
5763*26947304SEvan Yan 
5764*26947304SEvan Yan #ifdef DEBUG
5765*26947304SEvan Yan 		if (pcicfg_dump_fcode) {
5766*26947304SEvan Yan 			for (i = 0; i < 100; i++)
5767*26947304SEvan Yan 				DEBUG2("ROM 0x%x --> 0x%x\n", i,
5768*26947304SEvan Yan 				    ddi_get8(h, (uint8_t *)(addr + i)));
5769*26947304SEvan Yan 		}
5770*26947304SEvan Yan #endif
5771*26947304SEvan Yan 
5772*26947304SEvan Yan 		/*
5773*26947304SEvan Yan 		 * Some device say they have an Expansion ROM, but do not, so
5774*26947304SEvan Yan 		 * for non-21554 devices use peek so we don't panic due to
5775*26947304SEvan Yan 		 * accessing non existent memory.
5776*26947304SEvan Yan 		 */
5777*26947304SEvan Yan 		if (pcicfg_indirect_map(dip) == DDI_SUCCESS) {
5778*26947304SEvan Yan 			rom_sig = ddi_get16(h,
5779*26947304SEvan Yan 			    (uint16_t *)(addr + PCI_ROM_SIGNATURE));
5780*26947304SEvan Yan 		} else {
5781*26947304SEvan Yan 			if (ddi_peek16(dip,
5782*26947304SEvan Yan 			    (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) {
5783*26947304SEvan Yan 				cmn_err(CE_WARN,
5784*26947304SEvan Yan 				    "PCI Expansion ROM is not accessible");
5785*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &p);
5786*26947304SEvan Yan 				return (PCICFG_FAILURE);
5787*26947304SEvan Yan 			}
5788*26947304SEvan Yan 		}
5789*26947304SEvan Yan 
5790*26947304SEvan Yan 		/*
5791*26947304SEvan Yan 		 * Validate the ROM Signature.
5792*26947304SEvan Yan 		 */
5793*26947304SEvan Yan 		if ((uint16_t)rom_sig != 0xaa55) {
5794*26947304SEvan Yan 			DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig);
5795*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
5796*26947304SEvan Yan 			return (PCICFG_FAILURE);
5797*26947304SEvan Yan 		}
5798*26947304SEvan Yan 
5799*26947304SEvan Yan 		DEBUG0("Valid ROM Signature Found\n");
5800*26947304SEvan Yan 
5801*26947304SEvan Yan 		start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2));
5802*26947304SEvan Yan 
5803*26947304SEvan Yan 		pci_data =  ddi_get16(h,
5804*26947304SEvan Yan 		    (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR));
5805*26947304SEvan Yan 
5806*26947304SEvan Yan 		DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data,
5807*26947304SEvan Yan 		    addr);
5808*26947304SEvan Yan 
5809*26947304SEvan Yan 		/*
5810*26947304SEvan Yan 		 * Validate the PCI Data Structure Signature.
5811*26947304SEvan Yan 		 * 0x52494350 = "PCIR"
5812*26947304SEvan Yan 		 */
5813*26947304SEvan Yan 
5814*26947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) {
5815*26947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
5816*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
5817*26947304SEvan Yan 			return (PCICFG_FAILURE);
5818*26947304SEvan Yan 		}
5819*26947304SEvan Yan 
5820*26947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) {
5821*26947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
5822*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
5823*26947304SEvan Yan 			return (PCICFG_FAILURE);
5824*26947304SEvan Yan 		}
5825*26947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) {
5826*26947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
5827*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
5828*26947304SEvan Yan 			return (PCICFG_FAILURE);
5829*26947304SEvan Yan 		}
5830*26947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) {
5831*26947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
5832*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
5833*26947304SEvan Yan 			return (PCICFG_FAILURE);
5834*26947304SEvan Yan 		}
5835*26947304SEvan Yan 
5836*26947304SEvan Yan 		/*
5837*26947304SEvan Yan 		 * Is this image for this device?
5838*26947304SEvan Yan 		 */
5839*26947304SEvan Yan 		vendor_id_img = ddi_get16(h,
5840*26947304SEvan Yan 		    (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID));
5841*26947304SEvan Yan 		device_id_img = ddi_get16(h,
5842*26947304SEvan Yan 		    (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID));
5843*26947304SEvan Yan 
5844*26947304SEvan Yan 		DEBUG2("This image is for vendor_id=%x device_id=%x\n",
5845*26947304SEvan Yan 		    vendor_id_img, device_id_img);
5846*26947304SEvan Yan 
5847*26947304SEvan Yan 		code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE);
5848*26947304SEvan Yan 
5849*26947304SEvan Yan 		switch (code_type) {
5850*26947304SEvan Yan 		case PCI_PDS_CODE_TYPE_PCAT:
5851*26947304SEvan Yan 			DEBUG0("ROM is of x86/PC-AT Type\n");
5852*26947304SEvan Yan 			break;
5853*26947304SEvan Yan 		case PCI_PDS_CODE_TYPE_OPEN_FW:
5854*26947304SEvan Yan 			DEBUG0("ROM is of Open Firmware Type\n");
5855*26947304SEvan Yan 			break;
5856*26947304SEvan Yan 		default:
5857*26947304SEvan Yan 			DEBUG1("ROM is of Unknown Type 0x%x\n", code_type);
5858*26947304SEvan Yan 			break;
5859*26947304SEvan Yan 		}
5860*26947304SEvan Yan 
5861*26947304SEvan Yan 		if ((vendor_id_img != vendor_id) ||
5862*26947304SEvan Yan 		    (device_id_img != device_id) ||
5863*26947304SEvan Yan 		    (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) {
5864*26947304SEvan Yan 			DEBUG0("Firmware Image is not for this device..."
5865*26947304SEvan Yan 			    "goto next image\n");
5866*26947304SEvan Yan 			/*
5867*26947304SEvan Yan 			 * Read indicator byte to see if there is another
5868*26947304SEvan Yan 			 * image in the ROM
5869*26947304SEvan Yan 			 */
5870*26947304SEvan Yan 			indicator = ddi_get8(h,
5871*26947304SEvan Yan 			    (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR));
5872*26947304SEvan Yan 
5873*26947304SEvan Yan 			if (indicator != 1) {
5874*26947304SEvan Yan 				/*
5875*26947304SEvan Yan 				 * There is another image in the ROM.
5876*26947304SEvan Yan 				 */
5877*26947304SEvan Yan 				image_length = ddi_get16(h,  (uint16_t *)(addr +
5878*26947304SEvan Yan 				    pci_data + PCI_PDS_IMAGE_LENGTH)) * 512;
5879*26947304SEvan Yan 
5880*26947304SEvan Yan 				addr += image_length;
5881*26947304SEvan Yan 			} else {
5882*26947304SEvan Yan 				/*
5883*26947304SEvan Yan 				 * There are no more images.
5884*26947304SEvan Yan 				 */
5885*26947304SEvan Yan 				DEBUG0("There are no more images in the ROM\n");
5886*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &p);
5887*26947304SEvan Yan 
5888*26947304SEvan Yan 				return (PCICFG_FAILURE);
5889*26947304SEvan Yan 			}
5890*26947304SEvan Yan 		} else {
5891*26947304SEvan Yan 			DEBUG0("Correct image was found\n");
5892*26947304SEvan Yan 			image_not_found = 0;  /* Image was found */
5893*26947304SEvan Yan 		}
5894*26947304SEvan Yan 	}
5895*26947304SEvan Yan 
5896*26947304SEvan Yan 	*fcode_size =  (ddi_get8(h, addr + start_of_fcode + 4) << 24) |
5897*26947304SEvan Yan 	    (ddi_get8(h, addr + start_of_fcode + 5) << 16) |
5898*26947304SEvan Yan 	    (ddi_get8(h, addr + start_of_fcode + 6) << 8) |
5899*26947304SEvan Yan 	    (ddi_get8(h, addr + start_of_fcode + 7));
5900*26947304SEvan Yan 
5901*26947304SEvan Yan 	DEBUG1("Fcode Size %x\n", *fcode_size);
5902*26947304SEvan Yan 
5903*26947304SEvan Yan 	/*
5904*26947304SEvan Yan 	 * Allocate page aligned buffer space
5905*26947304SEvan Yan 	 */
5906*26947304SEvan Yan 	*fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP);
5907*26947304SEvan Yan 
5908*26947304SEvan Yan 	if (*fcode_addr == NULL) {
5909*26947304SEvan Yan 		DEBUG0("kmem_zalloc returned NULL\n");
5910*26947304SEvan Yan 		pcicfg_unmap_phys(&h, &p);
5911*26947304SEvan Yan 		return (PCICFG_FAILURE);
5912*26947304SEvan Yan 	}
5913*26947304SEvan Yan 
5914*26947304SEvan Yan 	DEBUG1("Fcode Addr %lx\n", *fcode_addr);
5915*26947304SEvan Yan 
5916*26947304SEvan Yan 	ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size,
5917*26947304SEvan Yan 	    DDI_DEV_AUTOINCR);
5918*26947304SEvan Yan 
5919*26947304SEvan Yan 	pcicfg_unmap_phys(&h, &p);
5920*26947304SEvan Yan 
5921*26947304SEvan Yan 	return (PCICFG_SUCCESS);
5922*26947304SEvan Yan }
5923*26947304SEvan Yan 
5924*26947304SEvan Yan static int
5925*26947304SEvan Yan pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus,
5926*26947304SEvan Yan     uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec)
5927*26947304SEvan Yan {
5928*26947304SEvan Yan 	/*
5929*26947304SEvan Yan 	 * Assign values to all BARs so that it is safe to turn on the
5930*26947304SEvan Yan 	 * device for accessing the fcode on the PROM. On successful
5931*26947304SEvan Yan 	 * exit from this function, "assigned-addresses" are created
5932*26947304SEvan Yan 	 * for all BARs and ROM BAR is enabled. Also, rom_regspec is
5933*26947304SEvan Yan 	 * filled with the values that can be used to free up this
5934*26947304SEvan Yan 	 * resource later.
5935*26947304SEvan Yan 	 */
5936*26947304SEvan Yan 	uint32_t request, hiword, size;
5937*26947304SEvan Yan 	pci_regspec_t phys_spec;
5938*26947304SEvan Yan 	ndi_ra_request_t req;
5939*26947304SEvan Yan 	uint64_t mem_answer, mem_alen;
5940*26947304SEvan Yan 	int i;
5941*26947304SEvan Yan 
5942*26947304SEvan Yan 	DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name);
5943*26947304SEvan Yan 
5944*26947304SEvan Yan 	/*
5945*26947304SEvan Yan 	 * Process the BARs.
5946*26947304SEvan Yan 	 */
5947*26947304SEvan Yan 	for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) {
5948*26947304SEvan Yan 		pci_config_put32(h, i, 0xffffffff);
5949*26947304SEvan Yan 		request = pci_config_get32(h, i);
5950*26947304SEvan Yan 		/*
5951*26947304SEvan Yan 		 * Check if implemented
5952*26947304SEvan Yan 		 */
5953*26947304SEvan Yan 		if (request == 0) {
5954*26947304SEvan Yan 			DEBUG1("pcicfg_fcode_assign_bars :"
5955*26947304SEvan Yan 			    "BASE register [0x%x] asks for 0(32)\n", i);
5956*26947304SEvan Yan 			i += 4;
5957*26947304SEvan Yan 			continue;
5958*26947304SEvan Yan 		}
5959*26947304SEvan Yan 		/*
5960*26947304SEvan Yan 		 * Build the phys_spec for this BAR
5961*26947304SEvan Yan 		 */
5962*26947304SEvan Yan 		hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i);
5963*26947304SEvan Yan 		size = (~(PCI_BASE_M_ADDR_M & request)) + 1;
5964*26947304SEvan Yan 
5965*26947304SEvan Yan 		DEBUG3("pcicfg_fcode_assign_bars :"
5966*26947304SEvan Yan 		    "BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
5967*26947304SEvan Yan 		    i, request, size);
5968*26947304SEvan Yan 
5969*26947304SEvan Yan 		if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) {
5970*26947304SEvan Yan 			if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) {
5971*26947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
5972*26947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & request)
5973*26947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
5974*26947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
5975*26947304SEvan Yan 			}
5976*26947304SEvan Yan 			if (request & PCI_BASE_PREF_M)
5977*26947304SEvan Yan 				hiword |= PCI_REG_PF_M;
5978*26947304SEvan Yan 		} else {
5979*26947304SEvan Yan 			hiword |= PCI_ADDR_IO;
5980*26947304SEvan Yan 		}
5981*26947304SEvan Yan 		phys_spec.pci_phys_hi = hiword;
5982*26947304SEvan Yan 		phys_spec.pci_phys_mid = 0;
5983*26947304SEvan Yan 		phys_spec.pci_phys_low = 0;
5984*26947304SEvan Yan 		phys_spec.pci_size_hi = 0;
5985*26947304SEvan Yan 		phys_spec.pci_size_low = size;
5986*26947304SEvan Yan 
5987*26947304SEvan Yan 		/*
5988*26947304SEvan Yan 		 * The following function
5989*26947304SEvan Yan 		 * - allocates address space
5990*26947304SEvan Yan 		 * - programs the BAR
5991*26947304SEvan Yan 		 * - adds an "assigned-addresses" property
5992*26947304SEvan Yan 		 */
5993*26947304SEvan Yan 		if (pcicfg_alloc_resource(dip, phys_spec)) {
5994*26947304SEvan Yan 			cmn_err(CE_WARN, "failed to allocate %d bytes"
5995*26947304SEvan Yan 			    " for dev %s BASE register [0x%x]\n",
5996*26947304SEvan Yan 			    size, DEVI(dip)->devi_name, i);
5997*26947304SEvan Yan 			goto failure;
5998*26947304SEvan Yan 		}
5999*26947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
6000*26947304SEvan Yan 			/*
6001*26947304SEvan Yan 			 * 64 bit, should be in memory space.
6002*26947304SEvan Yan 			 */
6003*26947304SEvan Yan 			i += 8;
6004*26947304SEvan Yan 		} else {
6005*26947304SEvan Yan 			/*
6006*26947304SEvan Yan 			 * 32 bit, either memory or I/O space.
6007*26947304SEvan Yan 			 */
6008*26947304SEvan Yan 			i += 4;
6009*26947304SEvan Yan 		}
6010*26947304SEvan Yan 	}
6011*26947304SEvan Yan 
6012*26947304SEvan Yan 	/*
6013*26947304SEvan Yan 	 * Handle ROM BAR. We do not use the common
6014*26947304SEvan Yan 	 * resource allocator function because we need to
6015*26947304SEvan Yan 	 * return reg spec to the caller.
6016*26947304SEvan Yan 	 */
6017*26947304SEvan Yan 	size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1;
6018*26947304SEvan Yan 
6019*26947304SEvan Yan 	DEBUG3("BASE register [0x%x] asks for "
6020*26947304SEvan Yan 	    "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size);
6021*26947304SEvan Yan 
6022*26947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
6023*26947304SEvan Yan 
6024*26947304SEvan Yan 	req.ra_boundbase = 0;
6025*26947304SEvan Yan 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
6026*26947304SEvan Yan 	req.ra_len = size;
6027*26947304SEvan Yan 	req.ra_flags |= NDI_RA_ALIGN_SIZE;
6028*26947304SEvan Yan 	req.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
6029*26947304SEvan Yan 
6030*26947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(dip),
6031*26947304SEvan Yan 	    &req, &mem_answer, &mem_alen,
6032*26947304SEvan Yan 	    NDI_RA_TYPE_MEM, NDI_RA_PASS)) {
6033*26947304SEvan Yan 		cmn_err(CE_WARN, "failed to allocate %d bytes"
6034*26947304SEvan Yan 		    " for dev %s ROM BASE register\n",
6035*26947304SEvan Yan 		    size, DEVI(dip)->devi_name);
6036*26947304SEvan Yan 		goto failure;
6037*26947304SEvan Yan 	}
6038*26947304SEvan Yan 
6039*26947304SEvan Yan 	DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
6040*26947304SEvan Yan 	    PCICFG_HIADDR(mem_answer),
6041*26947304SEvan Yan 	    PCICFG_LOADDR(mem_answer), mem_alen);
6042*26947304SEvan Yan 
6043*26947304SEvan Yan 	/*
6044*26947304SEvan Yan 	 * Assign address space and enable ROM.
6045*26947304SEvan Yan 	 */
6046*26947304SEvan Yan 	pci_config_put32(h, PCI_CONF_ROM,
6047*26947304SEvan Yan 	    PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE);
6048*26947304SEvan Yan 
6049*26947304SEvan Yan 	/*
6050*26947304SEvan Yan 	 * Add resource to assigned-addresses.
6051*26947304SEvan Yan 	 */
6052*26947304SEvan Yan 	phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \
6053*26947304SEvan Yan 	    PCI_CONF_ROM) | PCI_ADDR_MEM32;
6054*26947304SEvan Yan 	if (fc_request & PCI_BASE_PREF_M)
6055*26947304SEvan Yan 		phys_spec.pci_phys_hi |= PCI_REG_PF_M;
6056*26947304SEvan Yan 	phys_spec.pci_phys_mid = 0;
6057*26947304SEvan Yan 	phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer);
6058*26947304SEvan Yan 	phys_spec.pci_size_hi = 0;
6059*26947304SEvan Yan 	phys_spec.pci_size_low = size;
6060*26947304SEvan Yan 
6061*26947304SEvan Yan 	if (pcicfg_update_assigned_prop(dip, &phys_spec)
6062*26947304SEvan Yan 	    != PCICFG_SUCCESS) {
6063*26947304SEvan Yan 		cmn_err(CE_WARN, "failed to update"
6064*26947304SEvan Yan 		    " assigned-address property for dev %s\n",
6065*26947304SEvan Yan 		    DEVI(dip)->devi_name);
6066*26947304SEvan Yan 		goto failure;
6067*26947304SEvan Yan 	}
6068*26947304SEvan Yan 	/*
6069*26947304SEvan Yan 	 * Copy out the reg spec.
6070*26947304SEvan Yan 	 */
6071*26947304SEvan Yan 	*rom_regspec = phys_spec;
6072*26947304SEvan Yan 
6073*26947304SEvan Yan 	return (PCICFG_SUCCESS);
6074*26947304SEvan Yan 
6075*26947304SEvan Yan failure:
6076*26947304SEvan Yan 	/*
6077*26947304SEvan Yan 	 * We came in with no "assigned-addresses".
6078*26947304SEvan Yan 	 * Free up the resources we may have allocated.
6079*26947304SEvan Yan 	 */
6080*26947304SEvan Yan 	(void) pcicfg_free_device_resources(dip, 0);
6081*26947304SEvan Yan 
6082*26947304SEvan Yan 	return (PCICFG_FAILURE);
6083*26947304SEvan Yan }
6084*26947304SEvan Yan 
6085*26947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */
6086*26947304SEvan Yan 
6087*26947304SEvan Yan static int
6088*26947304SEvan Yan pcicfg_free_all_resources(dev_info_t *dip)
6089*26947304SEvan Yan {
6090*26947304SEvan Yan 	pci_regspec_t		*assigned;
6091*26947304SEvan Yan 	int			assigned_len;
6092*26947304SEvan Yan 	int			acount;
6093*26947304SEvan Yan 	int			i;
6094*26947304SEvan Yan 
6095*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
6096*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
6097*26947304SEvan Yan 	    &assigned_len) != DDI_PROP_SUCCESS) {
6098*26947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
6099*26947304SEvan Yan 		return (PCICFG_FAILURE);
6100*26947304SEvan Yan 	}
6101*26947304SEvan Yan 
6102*26947304SEvan Yan 	acount = assigned_len / sizeof (pci_regspec_t);
6103*26947304SEvan Yan 
6104*26947304SEvan Yan 	for (i = 0; i < acount; i++) {
6105*26947304SEvan Yan 		if (pcicfg_free_resource(dip, assigned[i], 0)) {
6106*26947304SEvan Yan 			/*
6107*26947304SEvan Yan 			 * Dont forget to free mem from ddi_getlongprop
6108*26947304SEvan Yan 			 */
6109*26947304SEvan Yan 			kmem_free((caddr_t)assigned, assigned_len);
6110*26947304SEvan Yan 			return (PCICFG_FAILURE);
6111*26947304SEvan Yan 		}
6112*26947304SEvan Yan 	}
6113*26947304SEvan Yan 
6114*26947304SEvan Yan 	/*
6115*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
6116*26947304SEvan Yan 	 */
6117*26947304SEvan Yan 	if (assigned_len)
6118*26947304SEvan Yan 		kmem_free((caddr_t)assigned, assigned_len);
6119*26947304SEvan Yan 
6120*26947304SEvan Yan 	return (PCICFG_SUCCESS);
6121*26947304SEvan Yan }
6122*26947304SEvan Yan static int
6123*26947304SEvan Yan pcicfg_alloc_new_resources(dev_info_t *dip)
6124*26947304SEvan Yan {
6125*26947304SEvan Yan 	pci_regspec_t		*assigned, *reg;
6126*26947304SEvan Yan 	int			assigned_len, reg_len;
6127*26947304SEvan Yan 	int			acount, rcount;
6128*26947304SEvan Yan 	int			i, j, alloc_size;
6129*26947304SEvan Yan 	boolean_t		alloc;
6130*26947304SEvan Yan 
6131*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
6132*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
6133*26947304SEvan Yan 	    &reg_len) != DDI_PROP_SUCCESS) {
6134*26947304SEvan Yan 		DEBUG0("Failed to read reg property\n");
6135*26947304SEvan Yan 		return (PCICFG_FAILURE);
6136*26947304SEvan Yan 	}
6137*26947304SEvan Yan 	rcount = reg_len / sizeof (pci_regspec_t);
6138*26947304SEvan Yan 
6139*26947304SEvan Yan 	DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n",
6140*26947304SEvan Yan 	    reg_len, rcount);
6141*26947304SEvan Yan 
6142*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
6143*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
6144*26947304SEvan Yan 	    &assigned_len) != DDI_PROP_SUCCESS) {
6145*26947304SEvan Yan 		acount = 0;
6146*26947304SEvan Yan 	} else {
6147*26947304SEvan Yan 		acount = assigned_len / sizeof (pci_regspec_t);
6148*26947304SEvan Yan 	}
6149*26947304SEvan Yan 
6150*26947304SEvan Yan 	DEBUG1("assigned-addresses property len=%x\n", acount);
6151*26947304SEvan Yan 
6152*26947304SEvan Yan 	/*
6153*26947304SEvan Yan 	 * For each address described by reg, search for it in the
6154*26947304SEvan Yan 	 * assigned-addresses property. If it does not exist, allocate
6155*26947304SEvan Yan 	 * resources for it. If it does exist, check the size in both.
6156*26947304SEvan Yan 	 * The size needs to be bigger of the two.
6157*26947304SEvan Yan 	 */
6158*26947304SEvan Yan 	for (i = 1; i < rcount; i++) {
6159*26947304SEvan Yan 		alloc = B_TRUE;
6160*26947304SEvan Yan 		alloc_size = reg[i].pci_size_low;
6161*26947304SEvan Yan 		for (j = 0; j < acount; j++) {
6162*26947304SEvan Yan 			if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) {
6163*26947304SEvan Yan 				/*
6164*26947304SEvan Yan 				 * There is an exact match. Check size.
6165*26947304SEvan Yan 				 */
6166*26947304SEvan Yan 				DEBUG1("pcicfg_alloc_new_resources "
6167*26947304SEvan Yan 				    "- %x - MATCH\n",
6168*26947304SEvan Yan 				    reg[i].pci_phys_hi);
6169*26947304SEvan Yan 
6170*26947304SEvan Yan 				if (reg[i].pci_size_low >
6171*26947304SEvan Yan 				    assigned[j].pci_size_low) {
6172*26947304SEvan Yan 					/*
6173*26947304SEvan Yan 					 * Fcode wants more.
6174*26947304SEvan Yan 					 */
6175*26947304SEvan Yan 					DEBUG3("pcicfg_alloc_new_resources"
6176*26947304SEvan Yan 					    " - %x - RESIZE"
6177*26947304SEvan Yan 					    " assigned 0x%x reg 0x%x\n",
6178*26947304SEvan Yan 					    assigned[j].pci_phys_hi,
6179*26947304SEvan Yan 					    assigned[j].pci_size_low,
6180*26947304SEvan Yan 					    reg[i].pci_size_low);
6181*26947304SEvan Yan 
6182*26947304SEvan Yan 					/*
6183*26947304SEvan Yan 					 * Free the old resource.
6184*26947304SEvan Yan 					 */
6185*26947304SEvan Yan 					(void) pcicfg_free_resource(dip,
6186*26947304SEvan Yan 					    assigned[j], 0);
6187*26947304SEvan Yan 				} else {
6188*26947304SEvan Yan 					DEBUG3("pcicfg_alloc_new_resources"
6189*26947304SEvan Yan 					    " - %x - ENOUGH"
6190*26947304SEvan Yan 					    " assigned 0x%x reg 0x%x\n",
6191*26947304SEvan Yan 					    assigned[j].pci_phys_hi,
6192*26947304SEvan Yan 					    assigned[j].pci_size_low,
6193*26947304SEvan Yan 					    reg[i].pci_size_low);
6194*26947304SEvan Yan 
6195*26947304SEvan Yan 					alloc = B_FALSE;
6196*26947304SEvan Yan 				}
6197*26947304SEvan Yan 				break;
6198*26947304SEvan Yan 			}
6199*26947304SEvan Yan 			/*
6200*26947304SEvan Yan 			 * Fcode may have set one or more of the
6201*26947304SEvan Yan 			 * NPT bits in phys.hi.
6202*26947304SEvan Yan 			 */
6203*26947304SEvan Yan 			if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) ==
6204*26947304SEvan Yan 			    PCI_REG_BDFR_G(reg[i].pci_phys_hi)) {
6205*26947304SEvan Yan 
6206*26947304SEvan Yan 				DEBUG2("pcicfg_alloc_new_resources "
6207*26947304SEvan Yan 				    "- PARTIAL MATCH assigned 0x%x "
6208*26947304SEvan Yan 				    "reg 0x%x\n", assigned[j].pci_phys_hi,
6209*26947304SEvan Yan 				    reg[i].pci_phys_hi);
6210*26947304SEvan Yan 				/*
6211*26947304SEvan Yan 				 * Changing the SS bits is an error
6212*26947304SEvan Yan 				 */
6213*26947304SEvan Yan 				if (PCI_REG_ADDR_G(
6214*26947304SEvan Yan 				    assigned[j].pci_phys_hi) !=
6215*26947304SEvan Yan 				    PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
6216*26947304SEvan Yan 
6217*26947304SEvan Yan 					DEBUG2("Fcode changing"
6218*26947304SEvan Yan 					    " SS bits of - 0x%x -"
6219*26947304SEvan Yan 					    " on %s\n", reg[i].pci_phys_hi,
6220*26947304SEvan Yan 					    DEVI(dip)->devi_name);
6221*26947304SEvan Yan 
6222*26947304SEvan Yan 				}
6223*26947304SEvan Yan 
6224*26947304SEvan Yan 
6225*26947304SEvan Yan 				/*
6226*26947304SEvan Yan 				 * We are going to allocate new resource.
6227*26947304SEvan Yan 				 * Free the old resource. Again, adjust
6228*26947304SEvan Yan 				 * the size to be safe.
6229*26947304SEvan Yan 				 */
6230*26947304SEvan Yan 				(void) pcicfg_free_resource(dip,
6231*26947304SEvan Yan 				    assigned[j], 0);
6232*26947304SEvan Yan 
6233*26947304SEvan Yan 				alloc_size = MAX(reg[i].pci_size_low,
6234*26947304SEvan Yan 				    assigned[j].pci_size_low);
6235*26947304SEvan Yan 
6236*26947304SEvan Yan 				break;
6237*26947304SEvan Yan 			}
6238*26947304SEvan Yan 		}
6239*26947304SEvan Yan 		/*
6240*26947304SEvan Yan 		 * We are allocating resources for one of three reasons -
6241*26947304SEvan Yan 		 * - Fcode wants a larger address space
6242*26947304SEvan Yan 		 * - Fcode has set changed/set n, p, t bits.
6243*26947304SEvan Yan 		 * - It is a new "reg", it should be only ROM bar, but
6244*26947304SEvan Yan 		 *   we don't do the checking.
6245*26947304SEvan Yan 		 */
6246*26947304SEvan Yan 		if (alloc == B_TRUE) {
6247*26947304SEvan Yan 			DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n",
6248*26947304SEvan Yan 			    reg[i].pci_phys_hi);
6249*26947304SEvan Yan 
6250*26947304SEvan Yan 			reg[i].pci_size_low = alloc_size;
6251*26947304SEvan Yan 			if (pcicfg_alloc_resource(dip, reg[i])) {
6252*26947304SEvan Yan 				/*
6253*26947304SEvan Yan 				 * Dont forget to free mem from
6254*26947304SEvan Yan 				 * ddi_getlongprop
6255*26947304SEvan Yan 				 */
6256*26947304SEvan Yan 				if (acount != 0)
6257*26947304SEvan Yan 					kmem_free((caddr_t)assigned,
6258*26947304SEvan Yan 					    assigned_len);
6259*26947304SEvan Yan 				kmem_free((caddr_t)reg, reg_len);
6260*26947304SEvan Yan 				return (PCICFG_FAILURE);
6261*26947304SEvan Yan 			}
6262*26947304SEvan Yan 		}
6263*26947304SEvan Yan 	}
6264*26947304SEvan Yan 
6265*26947304SEvan Yan 	/*
6266*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
6267*26947304SEvan Yan 	 */
6268*26947304SEvan Yan 	if (acount != 0)
6269*26947304SEvan Yan 		kmem_free((caddr_t)assigned, assigned_len);
6270*26947304SEvan Yan 	kmem_free((caddr_t)reg, reg_len);
6271*26947304SEvan Yan 
6272*26947304SEvan Yan 	return (PCICFG_SUCCESS);
6273*26947304SEvan Yan }
6274*26947304SEvan Yan 
6275*26947304SEvan Yan static int
6276*26947304SEvan Yan pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
6277*26947304SEvan Yan {
6278*26947304SEvan Yan 	uint64_t answer;
6279*26947304SEvan Yan 	uint64_t alen;
6280*26947304SEvan Yan 	int offset;
6281*26947304SEvan Yan 	pci_regspec_t config;
6282*26947304SEvan Yan 	caddr_t virt, v;
6283*26947304SEvan Yan 	ddi_device_acc_attr_t acc;
6284*26947304SEvan Yan 	ddi_acc_handle_t h;
6285*26947304SEvan Yan 	ndi_ra_request_t request;
6286*26947304SEvan Yan 	pci_regspec_t *assigned;
6287*26947304SEvan Yan 	int assigned_len, entries, i;
6288*26947304SEvan Yan 
6289*26947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
6290*26947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
6291*26947304SEvan Yan 	    &assigned_len) == DDI_PROP_SUCCESS) {
6292*26947304SEvan Yan 		DEBUG0("pcicfg_alloc_resource - "
6293*26947304SEvan Yan 		    "searching assigned-addresses\n");
6294*26947304SEvan Yan 
6295*26947304SEvan Yan 		entries = assigned_len / (sizeof (pci_regspec_t));
6296*26947304SEvan Yan 
6297*26947304SEvan Yan 		/*
6298*26947304SEvan Yan 		 * Walk through the assigned-addresses entries. If there is
6299*26947304SEvan Yan 		 * a match, there is no need to allocate the resource.
6300*26947304SEvan Yan 		 */
6301*26947304SEvan Yan 		for (i = 0; i < entries; i++) {
6302*26947304SEvan Yan 			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
6303*26947304SEvan Yan 				DEBUG1("pcicfg_alloc_resource - MATCH %x\n",
6304*26947304SEvan Yan 				    assigned[i].pci_phys_hi);
6305*26947304SEvan Yan 				kmem_free(assigned, assigned_len);
6306*26947304SEvan Yan 				return (0);
6307*26947304SEvan Yan 			}
6308*26947304SEvan Yan 		}
6309*26947304SEvan Yan 		kmem_free(assigned, assigned_len);
6310*26947304SEvan Yan 	}
6311*26947304SEvan Yan 
6312*26947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
6313*26947304SEvan Yan 
6314*26947304SEvan Yan 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
6315*26947304SEvan Yan 	config.pci_phys_hi &= ~PCI_REG_REG_M;
6316*26947304SEvan Yan 	config.pci_phys_mid = config.pci_phys_low = 0;
6317*26947304SEvan Yan 	config.pci_size_hi = config.pci_size_low = 0;
6318*26947304SEvan Yan 
6319*26947304SEvan Yan 	/*
6320*26947304SEvan Yan 	 * Map in configuration space (temporarily)
6321*26947304SEvan Yan 	 */
6322*26947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6323*26947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
6324*26947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6325*26947304SEvan Yan 
6326*26947304SEvan Yan 	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
6327*26947304SEvan Yan 		DEBUG0("Can not map in config space\n");
6328*26947304SEvan Yan 		return (1);
6329*26947304SEvan Yan 	}
6330*26947304SEvan Yan 
6331*26947304SEvan Yan 	request.ra_flags |= NDI_RA_ALIGN_SIZE;
6332*26947304SEvan Yan 	request.ra_boundbase = 0;
6333*26947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
6334*26947304SEvan Yan 	/*
6335*26947304SEvan Yan 	 * Use size stored in phys_spec parameter.
6336*26947304SEvan Yan 	 */
6337*26947304SEvan Yan 	request.ra_len = phys_spec.pci_size_low;
6338*26947304SEvan Yan 
6339*26947304SEvan Yan 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
6340*26947304SEvan Yan 
6341*26947304SEvan Yan 	v = virt + offset;
6342*26947304SEvan Yan 
6343*26947304SEvan Yan 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
6344*26947304SEvan Yan 
6345*26947304SEvan Yan 		request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
6346*26947304SEvan Yan 
6347*26947304SEvan Yan 		/* allocate memory space from the allocator */
6348*26947304SEvan Yan 
6349*26947304SEvan Yan 		if (ndi_ra_alloc(ddi_get_parent(dip),
6350*26947304SEvan Yan 		    &request, &answer, &alen,
6351*26947304SEvan Yan 		    NDI_RA_TYPE_MEM, NDI_RA_PASS)
6352*26947304SEvan Yan 		    != NDI_SUCCESS) {
6353*26947304SEvan Yan 			DEBUG0("(ROM)Failed to allocate 32b mem");
6354*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
6355*26947304SEvan Yan 			return (1);
6356*26947304SEvan Yan 		}
6357*26947304SEvan Yan 		DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
6358*26947304SEvan Yan 		    PCICFG_HIADDR(answer),
6359*26947304SEvan Yan 		    PCICFG_LOADDR(answer),
6360*26947304SEvan Yan 		    alen);
6361*26947304SEvan Yan 
6362*26947304SEvan Yan 		/* program the low word */
6363*26947304SEvan Yan 
6364*26947304SEvan Yan 		ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer));
6365*26947304SEvan Yan 
6366*26947304SEvan Yan 		phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
6367*26947304SEvan Yan 		phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
6368*26947304SEvan Yan 	} else {
6369*26947304SEvan Yan 
6370*26947304SEvan Yan 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
6371*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
6372*26947304SEvan Yan 			request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
6373*26947304SEvan Yan 			/* allocate memory space from the allocator */
6374*26947304SEvan Yan 			if (ndi_ra_alloc(ddi_get_parent(dip),
6375*26947304SEvan Yan 			    &request, &answer, &alen,
6376*26947304SEvan Yan 			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
6377*26947304SEvan Yan 			    != NDI_SUCCESS) {
6378*26947304SEvan Yan 				DEBUG0("Failed to allocate 64b mem\n");
6379*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
6380*26947304SEvan Yan 				return (1);
6381*26947304SEvan Yan 			}
6382*26947304SEvan Yan 			DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
6383*26947304SEvan Yan 			    PCICFG_HIADDR(answer),
6384*26947304SEvan Yan 			    PCICFG_LOADDR(answer),
6385*26947304SEvan Yan 			    alen);
6386*26947304SEvan Yan 
6387*26947304SEvan Yan 			/* program the low word */
6388*26947304SEvan Yan 
6389*26947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
6390*26947304SEvan Yan 			    (uint32_t)PCICFG_LOADDR(answer));
6391*26947304SEvan Yan 
6392*26947304SEvan Yan 			/* program the high word with value zero */
6393*26947304SEvan Yan 			v += 4;
6394*26947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
6395*26947304SEvan Yan 			    (uint32_t)PCICFG_HIADDR(answer));
6396*26947304SEvan Yan 
6397*26947304SEvan Yan 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
6398*26947304SEvan Yan 			phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
6399*26947304SEvan Yan 			/*
6400*26947304SEvan Yan 			 * currently support 32b address space
6401*26947304SEvan Yan 			 * assignments only.
6402*26947304SEvan Yan 			 */
6403*26947304SEvan Yan 			phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^
6404*26947304SEvan Yan 			    PCI_ADDR_MEM32;
6405*26947304SEvan Yan 
6406*26947304SEvan Yan 			break;
6407*26947304SEvan Yan 
6408*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
6409*26947304SEvan Yan 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
6410*26947304SEvan Yan 			/* allocate memory space from the allocator */
6411*26947304SEvan Yan 			if (ndi_ra_alloc(ddi_get_parent(dip),
6412*26947304SEvan Yan 			    &request, &answer, &alen,
6413*26947304SEvan Yan 			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
6414*26947304SEvan Yan 			    != NDI_SUCCESS) {
6415*26947304SEvan Yan 				DEBUG0("Failed to allocate 32b mem\n");
6416*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
6417*26947304SEvan Yan 				return (1);
6418*26947304SEvan Yan 			}
6419*26947304SEvan Yan 
6420*26947304SEvan Yan 			DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
6421*26947304SEvan Yan 			    PCICFG_HIADDR(answer),
6422*26947304SEvan Yan 			    PCICFG_LOADDR(answer),
6423*26947304SEvan Yan 			    alen);
6424*26947304SEvan Yan 
6425*26947304SEvan Yan 			/* program the low word */
6426*26947304SEvan Yan 
6427*26947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
6428*26947304SEvan Yan 			    (uint32_t)PCICFG_LOADDR(answer));
6429*26947304SEvan Yan 
6430*26947304SEvan Yan 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
6431*26947304SEvan Yan 
6432*26947304SEvan Yan 			break;
6433*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
6434*26947304SEvan Yan 			/* allocate I/O space from the allocator */
6435*26947304SEvan Yan 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
6436*26947304SEvan Yan 			if (ndi_ra_alloc(ddi_get_parent(dip),
6437*26947304SEvan Yan 			    &request, &answer, &alen,
6438*26947304SEvan Yan 			    NDI_RA_TYPE_IO, NDI_RA_PASS)
6439*26947304SEvan Yan 			    != NDI_SUCCESS) {
6440*26947304SEvan Yan 				DEBUG0("Failed to allocate I/O\n");
6441*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
6442*26947304SEvan Yan 				return (1);
6443*26947304SEvan Yan 			}
6444*26947304SEvan Yan 			DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
6445*26947304SEvan Yan 			    PCICFG_HIADDR(answer),
6446*26947304SEvan Yan 			    PCICFG_LOADDR(answer),
6447*26947304SEvan Yan 			    alen);
6448*26947304SEvan Yan 
6449*26947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
6450*26947304SEvan Yan 			    (uint32_t)PCICFG_LOADDR(answer));
6451*26947304SEvan Yan 
6452*26947304SEvan Yan 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
6453*26947304SEvan Yan 
6454*26947304SEvan Yan 			break;
6455*26947304SEvan Yan 		default:
6456*26947304SEvan Yan 			DEBUG0("Unknown register type\n");
6457*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
6458*26947304SEvan Yan 			return (1);
6459*26947304SEvan Yan 		} /* switch */
6460*26947304SEvan Yan 	}
6461*26947304SEvan Yan 
6462*26947304SEvan Yan 	/*
6463*26947304SEvan Yan 	 * Now that memory locations are assigned,
6464*26947304SEvan Yan 	 * update the assigned address property.
6465*26947304SEvan Yan 	 */
6466*26947304SEvan Yan 
6467*26947304SEvan Yan 	DEBUG1("updating assigned-addresss for %x\n",  phys_spec.pci_phys_hi);
6468*26947304SEvan Yan 
6469*26947304SEvan Yan 	if (pcicfg_update_assigned_prop(dip, &phys_spec)) {
6470*26947304SEvan Yan 		pcicfg_unmap_phys(&h, &config);
6471*26947304SEvan Yan 		return (1);
6472*26947304SEvan Yan 	}
6473*26947304SEvan Yan 
6474*26947304SEvan Yan 	pcicfg_unmap_phys(&h, &config);
6475*26947304SEvan Yan 
6476*26947304SEvan Yan 	return (0);
6477*26947304SEvan Yan }
6478*26947304SEvan Yan 
6479*26947304SEvan Yan static int
6480*26947304SEvan Yan pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec,
6481*26947304SEvan Yan     pcicfg_flags_t flags)
6482*26947304SEvan Yan {
6483*26947304SEvan Yan 	int offset;
6484*26947304SEvan Yan 	pci_regspec_t config;
6485*26947304SEvan Yan 	caddr_t virt, v;
6486*26947304SEvan Yan 	ddi_device_acc_attr_t acc;
6487*26947304SEvan Yan 	ddi_acc_handle_t h;
6488*26947304SEvan Yan 	ndi_ra_request_t request;
6489*26947304SEvan Yan 	int l;
6490*26947304SEvan Yan 
6491*26947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
6492*26947304SEvan Yan 
6493*26947304SEvan Yan 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
6494*26947304SEvan Yan 	config.pci_phys_hi &= ~PCI_REG_REG_M;
6495*26947304SEvan Yan 	config.pci_phys_mid = config.pci_phys_low = 0;
6496*26947304SEvan Yan 	config.pci_size_hi = config.pci_size_low = 0;
6497*26947304SEvan Yan 
6498*26947304SEvan Yan 	/*
6499*26947304SEvan Yan 	 * Map in configuration space (temporarily)
6500*26947304SEvan Yan 	 */
6501*26947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6502*26947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
6503*26947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6504*26947304SEvan Yan 
6505*26947304SEvan Yan 	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
6506*26947304SEvan Yan 		DEBUG0("Can not map in config space\n");
6507*26947304SEvan Yan 		return (1);
6508*26947304SEvan Yan 	}
6509*26947304SEvan Yan 
6510*26947304SEvan Yan 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
6511*26947304SEvan Yan 
6512*26947304SEvan Yan 	v = virt + offset;
6513*26947304SEvan Yan 
6514*26947304SEvan Yan 	/*
6515*26947304SEvan Yan 	 * Use size stored in phys_spec parameter.
6516*26947304SEvan Yan 	 */
6517*26947304SEvan Yan 	l = phys_spec.pci_size_low;
6518*26947304SEvan Yan 
6519*26947304SEvan Yan 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
6520*26947304SEvan Yan 
6521*26947304SEvan Yan 		/* free memory back to the allocator */
6522*26947304SEvan Yan 		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
6523*26947304SEvan Yan 		    l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
6524*26947304SEvan Yan 			DEBUG0("(ROM)Can not free 32b mem");
6525*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
6526*26947304SEvan Yan 			return (1);
6527*26947304SEvan Yan 		}
6528*26947304SEvan Yan 
6529*26947304SEvan Yan 		/* Unmap the BAR by writing a zero */
6530*26947304SEvan Yan 
6531*26947304SEvan Yan 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0)
6532*26947304SEvan Yan 			ddi_put32(h, (uint32_t *)v, (uint32_t)0);
6533*26947304SEvan Yan 	} else {
6534*26947304SEvan Yan 
6535*26947304SEvan Yan 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
6536*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
6537*26947304SEvan Yan 			/* free memory back to the allocator */
6538*26947304SEvan Yan 			if (ndi_ra_free(ddi_get_parent(dip),
6539*26947304SEvan Yan 			    PCICFG_LADDR(phys_spec.pci_phys_low,
6540*26947304SEvan Yan 			    phys_spec.pci_phys_mid),
6541*26947304SEvan Yan 			    l, NDI_RA_TYPE_MEM,
6542*26947304SEvan Yan 			    NDI_RA_PASS) != NDI_SUCCESS) {
6543*26947304SEvan Yan 				DEBUG0("Can not free 64b mem");
6544*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
6545*26947304SEvan Yan 				return (1);
6546*26947304SEvan Yan 			}
6547*26947304SEvan Yan 
6548*26947304SEvan Yan 			break;
6549*26947304SEvan Yan 
6550*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
6551*26947304SEvan Yan 			/* free memory back to the allocator */
6552*26947304SEvan Yan 			if (ndi_ra_free(ddi_get_parent(dip),
6553*26947304SEvan Yan 			    phys_spec.pci_phys_low,
6554*26947304SEvan Yan 			    l, NDI_RA_TYPE_MEM,
6555*26947304SEvan Yan 			    NDI_RA_PASS) != NDI_SUCCESS) {
6556*26947304SEvan Yan 				DEBUG0("Can not free 32b mem");
6557*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
6558*26947304SEvan Yan 				return (1);
6559*26947304SEvan Yan 			}
6560*26947304SEvan Yan 
6561*26947304SEvan Yan 			break;
6562*26947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
6563*26947304SEvan Yan 			/* free I/O space back to the allocator */
6564*26947304SEvan Yan 			if (ndi_ra_free(ddi_get_parent(dip),
6565*26947304SEvan Yan 			    phys_spec.pci_phys_low,
6566*26947304SEvan Yan 			    l, NDI_RA_TYPE_IO,
6567*26947304SEvan Yan 			    NDI_RA_PASS) != NDI_SUCCESS) {
6568*26947304SEvan Yan 				DEBUG0("Can not free I/O space");
6569*26947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
6570*26947304SEvan Yan 				return (1);
6571*26947304SEvan Yan 			}
6572*26947304SEvan Yan 
6573*26947304SEvan Yan 			break;
6574*26947304SEvan Yan 		default:
6575*26947304SEvan Yan 			DEBUG0("Unknown register type\n");
6576*26947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
6577*26947304SEvan Yan 			return (1);
6578*26947304SEvan Yan 		} /* switch */
6579*26947304SEvan Yan 	}
6580*26947304SEvan Yan 
6581*26947304SEvan Yan 	/*
6582*26947304SEvan Yan 	 * Now that memory locations are assigned,
6583*26947304SEvan Yan 	 * update the assigned address property.
6584*26947304SEvan Yan 	 */
6585*26947304SEvan Yan 
6586*26947304SEvan Yan 	DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi);
6587*26947304SEvan Yan 
6588*26947304SEvan Yan 	if (pcicfg_remove_assigned_prop(dip, &phys_spec)) {
6589*26947304SEvan Yan 		pcicfg_unmap_phys(&h, &config);
6590*26947304SEvan Yan 		return (1);
6591*26947304SEvan Yan 	}
6592*26947304SEvan Yan 
6593*26947304SEvan Yan 	pcicfg_unmap_phys(&h, &config);
6594*26947304SEvan Yan 
6595*26947304SEvan Yan 	return (0);
6596*26947304SEvan Yan }
6597*26947304SEvan Yan 
6598*26947304SEvan Yan static int
6599*26947304SEvan Yan pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
6600*26947304SEvan Yan {
6601*26947304SEvan Yan 	int		alen, num_entries, i;
6602*26947304SEvan Yan 	pci_regspec_t	*assigned, *assigned_copy;
6603*26947304SEvan Yan 	uint_t		status;
6604*26947304SEvan Yan 
6605*26947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
6606*26947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &alen);
6607*26947304SEvan Yan 	switch (status) {
6608*26947304SEvan Yan 		case DDI_PROP_SUCCESS:
6609*26947304SEvan Yan 		break;
6610*26947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
6611*26947304SEvan Yan 			DEBUG0("no memory for assigned-addresses property\n");
6612*26947304SEvan Yan 			return (1);
6613*26947304SEvan Yan 		default:
6614*26947304SEvan Yan 			DEBUG0("assigned-addresses property does not exist\n");
6615*26947304SEvan Yan 			return (0);
6616*26947304SEvan Yan 	}
6617*26947304SEvan Yan 
6618*26947304SEvan Yan 	/*
6619*26947304SEvan Yan 	 * Make a copy of old assigned-addresses property.
6620*26947304SEvan Yan 	 */
6621*26947304SEvan Yan 	assigned_copy = kmem_alloc(alen, KM_SLEEP);
6622*26947304SEvan Yan 	bcopy(assigned, assigned_copy, alen);
6623*26947304SEvan Yan 
6624*26947304SEvan Yan 	status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses");
6625*26947304SEvan Yan 
6626*26947304SEvan Yan 	if (status != DDI_PROP_SUCCESS) {
6627*26947304SEvan Yan 		/*
6628*26947304SEvan Yan 		 * If "assigned-addresses" is retrieved from PROM, the
6629*26947304SEvan Yan 		 * ndi_prop_remove() will fail.
6630*26947304SEvan Yan 		 */
6631*26947304SEvan Yan 		DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n",
6632*26947304SEvan Yan 		    oldone->pci_phys_hi);
6633*26947304SEvan Yan 
6634*26947304SEvan Yan 		/*
6635*26947304SEvan Yan 		 * Free up allocated memory
6636*26947304SEvan Yan 		 */
6637*26947304SEvan Yan 		kmem_free(assigned_copy, alen);
6638*26947304SEvan Yan 		kmem_free((caddr_t)assigned, alen);
6639*26947304SEvan Yan 
6640*26947304SEvan Yan 		return (0);
6641*26947304SEvan Yan 	}
6642*26947304SEvan Yan 
6643*26947304SEvan Yan 	num_entries = alen / sizeof (pci_regspec_t);
6644*26947304SEvan Yan 
6645*26947304SEvan Yan 	/*
6646*26947304SEvan Yan 	 * Rebuild the assigned-addresses property.
6647*26947304SEvan Yan 	 */
6648*26947304SEvan Yan 	for (i = 0; i < num_entries; i++) {
6649*26947304SEvan Yan 		if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) {
6650*26947304SEvan Yan 			(void) pcicfg_update_assigned_prop(dip,
6651*26947304SEvan Yan 			    &assigned_copy[i]);
6652*26947304SEvan Yan 		}
6653*26947304SEvan Yan 	}
6654*26947304SEvan Yan 
6655*26947304SEvan Yan 	/*
6656*26947304SEvan Yan 	 * Free the copy of the original assigned-addresses.
6657*26947304SEvan Yan 	 */
6658*26947304SEvan Yan 	kmem_free(assigned_copy, alen);
6659*26947304SEvan Yan 
6660*26947304SEvan Yan 	/*
6661*26947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
6662*26947304SEvan Yan 	 */
6663*26947304SEvan Yan 	kmem_free((caddr_t)assigned, alen);
6664*26947304SEvan Yan 
6665*26947304SEvan Yan 	return (0);
6666*26947304SEvan Yan }
6667*26947304SEvan Yan 
6668*26947304SEvan Yan static int
6669*26947304SEvan Yan pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
6670*26947304SEvan Yan 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
6671*26947304SEvan Yan 	ddi_acc_handle_t *handlep)
6672*26947304SEvan Yan {
6673*26947304SEvan Yan 	ddi_map_req_t mr;
6674*26947304SEvan Yan 	ddi_acc_hdl_t *hp;
6675*26947304SEvan Yan 	int result;
6676*26947304SEvan Yan 
6677*26947304SEvan Yan 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
6678*26947304SEvan Yan 	hp = impl_acc_hdl_get(*handlep);
6679*26947304SEvan Yan 	hp->ah_vers = VERS_ACCHDL;
6680*26947304SEvan Yan 	hp->ah_dip = dip;
6681*26947304SEvan Yan 	hp->ah_rnumber = 0;
6682*26947304SEvan Yan 	hp->ah_offset = 0;
6683*26947304SEvan Yan 	hp->ah_len = 0;
6684*26947304SEvan Yan 	hp->ah_acc = *accattrp;
6685*26947304SEvan Yan 
6686*26947304SEvan Yan 	mr.map_op = DDI_MO_MAP_LOCKED;
6687*26947304SEvan Yan 	mr.map_type = DDI_MT_REGSPEC;
6688*26947304SEvan Yan 	mr.map_obj.rp = (struct regspec *)phys_spec;
6689*26947304SEvan Yan 	mr.map_prot = PROT_READ | PROT_WRITE;
6690*26947304SEvan Yan 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
6691*26947304SEvan Yan 	mr.map_handlep = hp;
6692*26947304SEvan Yan 	mr.map_vers = DDI_MAP_VERSION;
6693*26947304SEvan Yan 
6694*26947304SEvan Yan 	result = ddi_map(dip, &mr, 0, 0, addrp);
6695*26947304SEvan Yan 
6696*26947304SEvan Yan 	if (result != DDI_SUCCESS) {
6697*26947304SEvan Yan 		impl_acc_hdl_free(*handlep);
6698*26947304SEvan Yan 		*handlep = (ddi_acc_handle_t)NULL;
6699*26947304SEvan Yan 	} else {
6700*26947304SEvan Yan 		hp->ah_addr = *addrp;
6701*26947304SEvan Yan 	}
6702*26947304SEvan Yan 
6703*26947304SEvan Yan 	return (result);
6704*26947304SEvan Yan }
6705*26947304SEvan Yan 
6706*26947304SEvan Yan void
6707*26947304SEvan Yan pcicfg_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
6708*26947304SEvan Yan {
6709*26947304SEvan Yan 	ddi_map_req_t mr;
6710*26947304SEvan Yan 	ddi_acc_hdl_t *hp;
6711*26947304SEvan Yan 
6712*26947304SEvan Yan 	hp = impl_acc_hdl_get(*handlep);
6713*26947304SEvan Yan 	ASSERT(hp);
6714*26947304SEvan Yan 
6715*26947304SEvan Yan 	mr.map_op = DDI_MO_UNMAP;
6716*26947304SEvan Yan 	mr.map_type = DDI_MT_REGSPEC;
6717*26947304SEvan Yan 	mr.map_obj.rp = (struct regspec *)ph;
6718*26947304SEvan Yan 	mr.map_prot = PROT_READ | PROT_WRITE;
6719*26947304SEvan Yan 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
6720*26947304SEvan Yan 	mr.map_handlep = hp;
6721*26947304SEvan Yan 	mr.map_vers = DDI_MAP_VERSION;
6722*26947304SEvan Yan 
6723*26947304SEvan Yan 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
6724*26947304SEvan Yan 	    hp->ah_len, &hp->ah_addr);
6725*26947304SEvan Yan 
6726*26947304SEvan Yan 	impl_acc_hdl_free(*handlep);
6727*26947304SEvan Yan 	*handlep = (ddi_acc_handle_t)NULL;
6728*26947304SEvan Yan }
6729*26947304SEvan Yan 
6730*26947304SEvan Yan static int
6731*26947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip)
6732*26947304SEvan Yan {
6733*26947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
6734*26947304SEvan Yan 		return (DDI_FAILURE);
6735*26947304SEvan Yan 
6736*26947304SEvan Yan 	/*
6737*26947304SEvan Yan 	 * Until we have resource balancing, dynamically configure
6738*26947304SEvan Yan 	 * ARI functions without firmware assistamce.
6739*26947304SEvan Yan 	 */
6740*26947304SEvan Yan 	return (DDI_FAILURE);
6741*26947304SEvan Yan }
6742*26947304SEvan Yan 
6743*26947304SEvan Yan #ifdef DEBUG
6744*26947304SEvan Yan static void
6745*26947304SEvan Yan debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
6746*26947304SEvan Yan 	uintptr_t a4, uintptr_t a5)
6747*26947304SEvan Yan {
6748*26947304SEvan Yan 	if (pcicfg_debug == 1) {
6749*26947304SEvan Yan 		prom_printf("pcicfg: ");
6750*26947304SEvan Yan 		prom_printf(fmt, a1, a2, a3, a4, a5);
6751*26947304SEvan Yan 	} else
6752*26947304SEvan Yan 		if (pcicfg_debug)
6753*26947304SEvan Yan 			cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
6754*26947304SEvan Yan }
6755*26947304SEvan Yan #endif
6756