xref: /titanic_53/usr/src/uts/sun4/io/pcicfg.c (revision 7f59ab1c87b64e613854fb759b15931264bd6307)
126947304SEvan Yan /*
226947304SEvan Yan  * CDDL HEADER START
326947304SEvan Yan  *
426947304SEvan Yan  * The contents of this file are subject to the terms of the
526947304SEvan Yan  * Common Development and Distribution License (the "License").
626947304SEvan Yan  * You may not use this file except in compliance with the License.
726947304SEvan Yan  *
826947304SEvan Yan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan  * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan  * See the License for the specific language governing permissions
1126947304SEvan Yan  * and limitations under the License.
1226947304SEvan Yan  *
1326947304SEvan Yan  * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan  * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan  * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan  * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan  *
1926947304SEvan Yan  * CDDL HEADER END
2026947304SEvan Yan  */
2126947304SEvan Yan /*
22*7f59ab1cSAlan Adamson, SD OSSD  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2326947304SEvan Yan  */
2426947304SEvan Yan 
2526947304SEvan Yan /*
2626947304SEvan Yan  *     PCI configurator (pcicfg)
2726947304SEvan Yan  */
2826947304SEvan Yan 
2926947304SEvan Yan #include <sys/isa_defs.h>
3026947304SEvan Yan 
3126947304SEvan Yan #include <sys/conf.h>
3226947304SEvan Yan #include <sys/kmem.h>
3326947304SEvan Yan #include <sys/debug.h>
3426947304SEvan Yan #include <sys/modctl.h>
3526947304SEvan Yan #include <sys/autoconf.h>
3626947304SEvan Yan #include <sys/hwconf.h>
3726947304SEvan Yan #include <sys/ddi_impldefs.h>
3826947304SEvan Yan #include <sys/fcode.h>
3926947304SEvan Yan #include <sys/pci.h>
4026947304SEvan Yan #include <sys/pcie.h>
4126947304SEvan Yan #include <sys/pcie_impl.h>
4226947304SEvan Yan #include <sys/ddi.h>
4326947304SEvan Yan #include <sys/sunddi.h>
4426947304SEvan Yan #include <sys/sunndi.h>
4526947304SEvan Yan #include <sys/pci_cap.h>
4626947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h>
4726947304SEvan Yan #include <sys/ndi_impldefs.h>
48c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
4926947304SEvan Yan 
5026947304SEvan Yan #define	PCICFG_DEVICE_TYPE_PCI	1
5126947304SEvan Yan #define	PCICFG_DEVICE_TYPE_PCIE	2
5226947304SEvan Yan 
5326947304SEvan Yan #define	EFCODE21554	/* changes for supporting 21554 */
5426947304SEvan Yan 
5526947304SEvan Yan static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t);
5626947304SEvan Yan static int pcicfg_free_resource(dev_info_t *, pci_regspec_t, pcicfg_flags_t);
5726947304SEvan Yan static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
5826947304SEvan Yan 
5926947304SEvan Yan #ifdef	PCICFG_INTERPRET_FCODE
6026947304SEvan Yan static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *,
6126947304SEvan Yan     uint_t, uint_t, uint_t, int32_t, pci_regspec_t *);
6226947304SEvan Yan #endif	/* PCICFG_INTERPRET_FCODE */
6326947304SEvan Yan 
6426947304SEvan Yan /*
6526947304SEvan Yan  * ************************************************************************
6626947304SEvan Yan  * *** Implementation specific local data structures/definitions.	***
6726947304SEvan Yan  * ************************************************************************
6826947304SEvan Yan  */
6926947304SEvan Yan 
7026947304SEvan Yan static	int	pcicfg_start_devno = 0;	/* for Debug only */
7126947304SEvan Yan 
7226947304SEvan Yan #define	PCICFG_MAX_DEVICE 32
7326947304SEvan Yan #define	PCICFG_MAX_FUNCTION 8
7426947304SEvan Yan #define	PCICFG_MAX_ARI_FUNCTION 256
7526947304SEvan Yan #define	PCICFG_MAX_REGISTER 64
7626947304SEvan Yan #define	PCICFG_MAX_BUS_DEPTH 255
7726947304SEvan Yan 
7826947304SEvan Yan #define	PCICFG_NODEVICE 42
7926947304SEvan Yan #define	PCICFG_NOMEMORY 43
8026947304SEvan Yan #define	PCICFG_NOMULTI	44
8126947304SEvan Yan 
8226947304SEvan Yan #define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
8326947304SEvan Yan #define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
8426947304SEvan Yan #define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
8526947304SEvan Yan 
8626947304SEvan Yan #define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
8726947304SEvan Yan #define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
8826947304SEvan Yan #define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
8926947304SEvan Yan #define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
9026947304SEvan Yan 
9126947304SEvan Yan #define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
9226947304SEvan Yan #define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
9326947304SEvan Yan 
9426947304SEvan Yan #define	PCICFG_MEMGRAN 0x100000
9526947304SEvan Yan #define	PCICFG_IOGRAN 0x1000
9626947304SEvan Yan #define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
9726947304SEvan Yan 
9826947304SEvan Yan #define	PCICFG_MEM_MULT 4
9926947304SEvan Yan #define	PCICFG_IO_MULT 4
10026947304SEvan Yan #define	PCICFG_RANGE_LEN 2 /* Number of range entries */
10126947304SEvan Yan 
10226947304SEvan Yan static int pcicfg_slot_busnums = 8;
10326947304SEvan Yan static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
10426947304SEvan Yan static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */
10526947304SEvan Yan static int pcicfg_chassis_per_tree = 1;
10626947304SEvan Yan static int pcicfg_sec_reset_delay = 1000000;
10726947304SEvan Yan 
10826947304SEvan Yan /*
10926947304SEvan Yan  * The following typedef is used to represent a
11026947304SEvan Yan  * 1275 "bus-range" property of a PCI Bus node.
11126947304SEvan Yan  * DAF - should be in generic include file...
11226947304SEvan Yan  */
11326947304SEvan Yan 
11426947304SEvan Yan typedef struct pcicfg_bus_range {
11526947304SEvan Yan 	uint32_t lo;
11626947304SEvan Yan 	uint32_t hi;
11726947304SEvan Yan } pcicfg_bus_range_t;
11826947304SEvan Yan 
11926947304SEvan Yan typedef struct pcicfg_range {
12026947304SEvan Yan 
12126947304SEvan Yan 	uint32_t child_hi;
12226947304SEvan Yan 	uint32_t child_mid;
12326947304SEvan Yan 	uint32_t child_lo;
12426947304SEvan Yan 	uint32_t parent_hi;
12526947304SEvan Yan 	uint32_t parent_mid;
12626947304SEvan Yan 	uint32_t parent_lo;
12726947304SEvan Yan 	uint32_t size_hi;
12826947304SEvan Yan 	uint32_t size_lo;
12926947304SEvan Yan 
13026947304SEvan Yan } pcicfg_range_t;
13126947304SEvan Yan 
13226947304SEvan Yan typedef struct hole hole_t;
13326947304SEvan Yan 
13426947304SEvan Yan struct hole {
13526947304SEvan Yan 	uint64_t	start;
13626947304SEvan Yan 	uint64_t	len;
13726947304SEvan Yan 	hole_t		*next;
13826947304SEvan Yan };
13926947304SEvan Yan 
14026947304SEvan Yan typedef struct pcicfg_phdl pcicfg_phdl_t;
14126947304SEvan Yan 
14226947304SEvan Yan struct pcicfg_phdl {
14326947304SEvan Yan 
14426947304SEvan Yan 	dev_info_t	*dip;		/* Associated with the attach point */
14526947304SEvan Yan 	pcicfg_phdl_t	*next;
14626947304SEvan Yan 
14726947304SEvan Yan 	uint64_t	memory_base;	/* Memory base for this attach point */
14826947304SEvan Yan 	uint64_t	memory_last;
14926947304SEvan Yan 	uint64_t	memory_len;
15026947304SEvan Yan 	uint32_t	io_base;	/* I/O base for this attach point */
15126947304SEvan Yan 	uint32_t	io_last;
15226947304SEvan Yan 	uint32_t	io_len;
15326947304SEvan Yan 
15426947304SEvan Yan 	int		error;
15526947304SEvan Yan 	uint_t		highest_bus;	/* Highest bus seen on the probe */
15626947304SEvan Yan 
15726947304SEvan Yan 	hole_t		mem_hole;	/* Memory hole linked list. */
15826947304SEvan Yan 	hole_t		io_hole;	/* IO hole linked list */
15926947304SEvan Yan 
16026947304SEvan Yan 	ndi_ra_request_t mem_req;	/* allocator request for memory */
16126947304SEvan Yan 	ndi_ra_request_t io_req;	/* allocator request for I/O */
16226947304SEvan Yan };
16326947304SEvan Yan 
16426947304SEvan Yan struct pcicfg_standard_prop_entry {
16526947304SEvan Yan     uchar_t *name;
16626947304SEvan Yan     uint_t  config_offset;
16726947304SEvan Yan     uint_t  size;
16826947304SEvan Yan };
16926947304SEvan Yan 
17026947304SEvan Yan 
17126947304SEvan Yan struct pcicfg_name_entry {
17226947304SEvan Yan     uint32_t class_code;
17326947304SEvan Yan     char  *name;
17426947304SEvan Yan };
17526947304SEvan Yan 
17626947304SEvan Yan struct pcicfg_find_ctrl {
17726947304SEvan Yan 	uint_t		device;
17826947304SEvan Yan 	uint_t		function;
17926947304SEvan Yan 	dev_info_t	*dip;
18026947304SEvan Yan };
18126947304SEvan Yan 
18226947304SEvan Yan typedef struct pcicfg_err_regs {
18326947304SEvan Yan 	uint16_t cmd;
18426947304SEvan Yan 	uint16_t bcntl;
18526947304SEvan Yan 	uint16_t pcie_dev;
18626947304SEvan Yan 	uint16_t devctl;
18726947304SEvan Yan 	uint16_t pcie_cap_off;
18826947304SEvan Yan } pcicfg_err_regs_t;
18926947304SEvan Yan 
19026947304SEvan Yan /*
19126947304SEvan Yan  * List of Indirect Config Map Devices. At least the intent of the
19226947304SEvan Yan  * design is to look for a device in this list during the configure
19326947304SEvan Yan  * operation, and if the device is listed here, then it is a nontransparent
19426947304SEvan Yan  * bridge, hence load the driver and avail the config map services from
19526947304SEvan Yan  * the driver. Class and Subclass should be as defined in the PCI specs
19626947304SEvan Yan  * ie. class is 0x6, and subclass is 0x9.
19726947304SEvan Yan  */
19826947304SEvan Yan static struct {
19926947304SEvan Yan 	uint8_t		mem_range_bar_offset;
20026947304SEvan Yan 	uint8_t		io_range_bar_offset;
20126947304SEvan Yan 	uint8_t		prefetch_mem_range_bar_offset;
20226947304SEvan Yan } pcicfg_indirect_map_devs[] = {
20326947304SEvan Yan 	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
20426947304SEvan Yan 	0,	0,	0,
20526947304SEvan Yan };
20626947304SEvan Yan 
20726947304SEvan Yan #define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
20826947304SEvan Yan 	(\
20926947304SEvan Yan 	((ulong_t)(busnum & 0xff) << 16)    |\
21026947304SEvan Yan 	((ulong_t)(devnum & 0x1f) << 11)    |\
21126947304SEvan Yan 	((ulong_t)(funcnum & 0x7) <<  8)    |\
21226947304SEvan Yan 	((ulong_t)(register & 0x3f)))
21326947304SEvan Yan 
21426947304SEvan Yan /*
21526947304SEvan Yan  * debug macros:
21626947304SEvan Yan  */
21726947304SEvan Yan #if	defined(DEBUG)
21826947304SEvan Yan extern void prom_printf(const char *, ...);
21926947304SEvan Yan 
22026947304SEvan Yan /*
22126947304SEvan Yan  * Following values are defined for this debug flag.
22226947304SEvan Yan  *
22326947304SEvan Yan  * 1 = dump configuration header only.
22426947304SEvan Yan  * 2 = dump generic debug data only (no config header dumped)
22526947304SEvan Yan  * 3 = dump everything (both 1 and 2)
22626947304SEvan Yan  */
22726947304SEvan Yan int pcicfg_debug = 0;
22826947304SEvan Yan int pcicfg_dump_fcode = 0;
22926947304SEvan Yan 
23026947304SEvan Yan static void debug(char *, uintptr_t, uintptr_t,
23126947304SEvan Yan 	uintptr_t, uintptr_t, uintptr_t);
23226947304SEvan Yan 
23326947304SEvan Yan #define	DEBUG0(fmt)\
23426947304SEvan Yan 	debug(fmt, 0, 0, 0, 0, 0);
23526947304SEvan Yan #define	DEBUG1(fmt, a1)\
23626947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
23726947304SEvan Yan #define	DEBUG2(fmt, a1, a2)\
23826947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
23926947304SEvan Yan #define	DEBUG3(fmt, a1, a2, a3)\
24026947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
24126947304SEvan Yan 		(uintptr_t)(a3), 0, 0);
24226947304SEvan Yan #define	DEBUG4(fmt, a1, a2, a3, a4)\
24326947304SEvan Yan 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
24426947304SEvan Yan 		(uintptr_t)(a3), (uintptr_t)(a4), 0);
24526947304SEvan Yan #else
24626947304SEvan Yan #define	DEBUG0(fmt)
24726947304SEvan Yan #define	DEBUG1(fmt, a1)
24826947304SEvan Yan #define	DEBUG2(fmt, a1, a2)
24926947304SEvan Yan #define	DEBUG3(fmt, a1, a2, a3)
25026947304SEvan Yan #define	DEBUG4(fmt, a1, a2, a3, a4)
25126947304SEvan Yan #endif
25226947304SEvan Yan 
25326947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
25426947304SEvan Yan int pcicfg_dont_interpret = 0;
25526947304SEvan Yan #else
25626947304SEvan Yan int pcicfg_dont_interpret = 1;
25726947304SEvan Yan #endif
25826947304SEvan Yan 
25926947304SEvan Yan /*
26026947304SEvan Yan  * forward declarations for routines defined in this module (called here)
26126947304SEvan Yan  */
26226947304SEvan Yan 
26326947304SEvan Yan static int pcicfg_add_config_reg(dev_info_t *,
26426947304SEvan Yan     uint_t, uint_t, uint_t);
26526947304SEvan Yan static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
266c0da6274SZhi-Jun Robin Fu     uint_t *, pcicfg_flags_t, boolean_t);
26726947304SEvan Yan 
26826947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
26926947304SEvan Yan static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
27026947304SEvan Yan 	uint16_t, uint16_t, uchar_t **, int *, int, int);
27126947304SEvan Yan #endif
27226947304SEvan Yan 
27326947304SEvan Yan static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t,
274c0da6274SZhi-Jun Robin Fu     uint_t *, pcicfg_flags_t, boolean_t);
27526947304SEvan Yan static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
276c0da6274SZhi-Jun Robin Fu     uint_t *, boolean_t);
27726947304SEvan Yan static int pcicfg_free_all_resources(dev_info_t *);
27826947304SEvan Yan static int pcicfg_alloc_new_resources(dev_info_t *);
27926947304SEvan Yan static int pcicfg_match_dev(dev_info_t *, void *);
28026947304SEvan Yan static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
28126947304SEvan Yan static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
28226947304SEvan Yan static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
28326947304SEvan Yan static int pcicfg_destroy_phdl(dev_info_t *);
28426947304SEvan Yan static int pcicfg_sum_resources(dev_info_t *, void *);
28526947304SEvan Yan static int pcicfg_find_resource_end(dev_info_t *, void *);
28626947304SEvan Yan static int pcicfg_allocate_chunk(dev_info_t *);
28726947304SEvan Yan static int pcicfg_program_ap(dev_info_t *);
28826947304SEvan Yan static int pcicfg_device_assign(dev_info_t *);
28926947304SEvan Yan static int pcicfg_bridge_assign(dev_info_t *, void *);
29026947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *);
29126947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
29226947304SEvan Yan static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t,
29326947304SEvan Yan     dev_info_t *);
29426947304SEvan Yan static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
29526947304SEvan Yan static void pcicfg_enable_bridge_probe_err(dev_info_t *dip,
29626947304SEvan Yan 				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
29726947304SEvan Yan static void pcicfg_disable_bridge_probe_err(dev_info_t *dip,
29826947304SEvan Yan 				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
29926947304SEvan Yan static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
30026947304SEvan Yan static void pcicfg_device_on(ddi_acc_handle_t);
30126947304SEvan Yan static void pcicfg_device_off(ddi_acc_handle_t);
30226947304SEvan Yan static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int);
30326947304SEvan Yan static int pcicfg_free_bridge_resources(dev_info_t *);
30426947304SEvan Yan static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t);
305c0da6274SZhi-Jun Robin Fu static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
30626947304SEvan Yan static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
30726947304SEvan Yan static void pcicfg_config_teardown(ddi_acc_handle_t *);
30826947304SEvan Yan static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
30926947304SEvan Yan static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
31026947304SEvan Yan static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *);
31126947304SEvan Yan static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *,
31226947304SEvan Yan     ddi_device_acc_attr_t *, ddi_acc_handle_t *);
31326947304SEvan Yan static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
31426947304SEvan Yan static int pcicfg_dump_assigned(dev_info_t *);
31526947304SEvan Yan static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
31626947304SEvan Yan static int pcicfg_indirect_map(dev_info_t *dip);
31726947304SEvan Yan static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
31826947304SEvan Yan 				uint64_t *, uint_t);
31926947304SEvan Yan static int pcicfg_is_ntbridge(dev_info_t *);
32026947304SEvan Yan static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
32126947304SEvan Yan static int pcicfg_ntbridge_configure_done(dev_info_t *);
32226947304SEvan Yan static int pcicfg_ntbridge_unconfigure(dev_info_t *);
32326947304SEvan Yan static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
32426947304SEvan Yan static void pcicfg_free_hole(hole_t *);
32526947304SEvan Yan static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
32626947304SEvan Yan static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *);
32726947304SEvan Yan static int pcicfg_ari_configure(dev_info_t *);
32826947304SEvan Yan static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
32926947304SEvan Yan static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
33026947304SEvan Yan static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
33126947304SEvan Yan     uint32_t, uint32_t, uint_t);
332c0da6274SZhi-Jun Robin Fu static boolean_t is_pcie_fabric(dev_info_t *dip);
33326947304SEvan Yan 
33426947304SEvan Yan #ifdef DEBUG
33526947304SEvan Yan static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
33626947304SEvan Yan static void pcicfg_dump_device_config(ddi_acc_handle_t);
33726947304SEvan Yan 
33826947304SEvan Yan static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
33926947304SEvan Yan static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
34026947304SEvan Yan 
34126947304SEvan Yan #define	PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
34226947304SEvan Yan #define	PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
34326947304SEvan Yan #define	PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
34426947304SEvan Yan #else
34526947304SEvan Yan #define	PCICFG_DUMP_COMMON_CONFIG(handle)
34626947304SEvan Yan #define	PCICFG_DUMP_DEVICE_CONFIG(handle)
34726947304SEvan Yan #define	PCICFG_DUMP_BRIDGE_CONFIG(handle)
34826947304SEvan Yan #endif
34926947304SEvan Yan 
35026947304SEvan Yan static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
35126947304SEvan Yan static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
35226947304SEvan Yan 
35326947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES
35426947304SEvan Yan /*
35526947304SEvan Yan  * Class code table
35626947304SEvan Yan  */
35726947304SEvan Yan static struct pcicfg_name_entry pcicfg_class_lookup [] = {
35826947304SEvan Yan 
35926947304SEvan Yan 	{ 0x001, "display" },
36026947304SEvan Yan 	{ 0x100, "scsi" },
36126947304SEvan Yan 	{ 0x101, "ide" },
36226947304SEvan Yan 	{ 0x102, "fdc" },
36326947304SEvan Yan 	{ 0x103, "ipi" },
36426947304SEvan Yan 	{ 0x104, "raid" },
36526947304SEvan Yan 	{ 0x200, "ethernet" },
36626947304SEvan Yan 	{ 0x201, "token-ring" },
36726947304SEvan Yan 	{ 0x202, "fddi" },
36826947304SEvan Yan 	{ 0x203, "atm" },
36926947304SEvan Yan 	{ 0x300, "display" },
37026947304SEvan Yan 	{ 0x400, "video" },
37126947304SEvan Yan 	{ 0x401, "sound" },
37226947304SEvan Yan 	{ 0x500, "memory" },
37326947304SEvan Yan 	{ 0x501, "flash" },
37426947304SEvan Yan 	{ 0x600, "host" },
37526947304SEvan Yan 	{ 0x601, "isa" },
37626947304SEvan Yan 	{ 0x602, "eisa" },
37726947304SEvan Yan 	{ 0x603, "mca" },
37826947304SEvan Yan 	{ 0x604, "pci" },
37926947304SEvan Yan 	{ 0x605, "pcmcia" },
38026947304SEvan Yan 	{ 0x606, "nubus" },
38126947304SEvan Yan 	{ 0x607, "cardbus" },
38226947304SEvan Yan 	{ 0x609, "pci" },
38326947304SEvan Yan 	{ 0x700, "serial" },
38426947304SEvan Yan 	{ 0x701, "parallel" },
38526947304SEvan Yan 	{ 0x800, "interrupt-controller" },
38626947304SEvan Yan 	{ 0x801, "dma-controller" },
38726947304SEvan Yan 	{ 0x802, "timer" },
38826947304SEvan Yan 	{ 0x803, "rtc" },
38926947304SEvan Yan 	{ 0x900, "keyboard" },
39026947304SEvan Yan 	{ 0x901, "pen" },
39126947304SEvan Yan 	{ 0x902, "mouse" },
39226947304SEvan Yan 	{ 0xa00, "dock" },
39326947304SEvan Yan 	{ 0xb00, "cpu" },
39426947304SEvan Yan 	{ 0xc00, "firewire" },
39526947304SEvan Yan 	{ 0xc01, "access-bus" },
39626947304SEvan Yan 	{ 0xc02, "ssa" },
39726947304SEvan Yan 	{ 0xc03, "usb" },
39826947304SEvan Yan 	{ 0xc04, "fibre-channel" },
39926947304SEvan Yan 	{ 0, 0 }
40026947304SEvan Yan };
40126947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */
40226947304SEvan Yan 
40326947304SEvan Yan /*
40426947304SEvan Yan  * Module control operations
40526947304SEvan Yan  */
40626947304SEvan Yan 
40726947304SEvan Yan extern struct mod_ops mod_miscops;
40826947304SEvan Yan 
40926947304SEvan Yan static struct modlmisc modlmisc = {
41026947304SEvan Yan 	&mod_miscops, /* Type of module */
41126947304SEvan Yan 	"PCIe/PCI Config (EFCode Enabled)"
41226947304SEvan Yan };
41326947304SEvan Yan 
41426947304SEvan Yan static struct modlinkage modlinkage = {
41526947304SEvan Yan 	MODREV_1, (void *)&modlmisc, NULL
41626947304SEvan Yan };
41726947304SEvan Yan 
41826947304SEvan Yan #ifdef DEBUG
41926947304SEvan Yan 
42026947304SEvan Yan static void
42126947304SEvan Yan pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
42226947304SEvan Yan {
42326947304SEvan Yan 	if ((pcicfg_debug & 1) == 0)
42426947304SEvan Yan 		return;
42526947304SEvan Yan 	cmn_err(CE_CONT, " Vendor ID   = [0x%x]\n",
42626947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID));
42726947304SEvan Yan 	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
42826947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
42926947304SEvan Yan 	cmn_err(CE_CONT, " Command REG = [0x%x]\n",
43026947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_COMM));
43126947304SEvan Yan 	cmn_err(CE_CONT, " Status  REG = [0x%x]\n",
43226947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_STAT));
43326947304SEvan Yan 	cmn_err(CE_CONT, " Revision ID = [0x%x]\n",
43426947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_REVID));
43526947304SEvan Yan 	cmn_err(CE_CONT, " Prog Class  = [0x%x]\n",
43626947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
43726947304SEvan Yan 	cmn_err(CE_CONT, " Dev Class   = [0x%x]\n",
43826947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
43926947304SEvan Yan 	cmn_err(CE_CONT, " Base Class  = [0x%x]\n",
44026947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
44126947304SEvan Yan 	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
44226947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
44326947304SEvan Yan 	cmn_err(CE_CONT, " Header Type = [0x%x]\n",
44426947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_HEADER));
44526947304SEvan Yan 	cmn_err(CE_CONT, " BIST        = [0x%x]\n",
44626947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_BIST));
44726947304SEvan Yan 	cmn_err(CE_CONT, " BASE 0      = [0x%x]\n",
44826947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE0));
44926947304SEvan Yan 	cmn_err(CE_CONT, " BASE 1      = [0x%x]\n",
45026947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE1));
45126947304SEvan Yan 
45226947304SEvan Yan }
45326947304SEvan Yan 
45426947304SEvan Yan static void
45526947304SEvan Yan pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
45626947304SEvan Yan {
45726947304SEvan Yan 	if ((pcicfg_debug & 1) == 0)
45826947304SEvan Yan 		return;
45926947304SEvan Yan 	pcicfg_dump_common_config(config_handle);
46026947304SEvan Yan 
46126947304SEvan Yan 	cmn_err(CE_CONT, " BASE 2      = [0x%x]\n",
46226947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE2));
46326947304SEvan Yan 	cmn_err(CE_CONT, " BASE 3      = [0x%x]\n",
46426947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE3));
46526947304SEvan Yan 	cmn_err(CE_CONT, " BASE 4      = [0x%x]\n",
46626947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE4));
46726947304SEvan Yan 	cmn_err(CE_CONT, " BASE 5      = [0x%x]\n",
46826947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE5));
46926947304SEvan Yan 	cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n",
47026947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_CIS));
47126947304SEvan Yan 	cmn_err(CE_CONT, " Sub VID     = [0x%x]\n",
47226947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
47326947304SEvan Yan 	cmn_err(CE_CONT, " Sub SID     = [0x%x]\n",
47426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
47526947304SEvan Yan 	cmn_err(CE_CONT, " ROM         = [0x%x]\n",
47626947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_ROM));
47726947304SEvan Yan 	cmn_err(CE_CONT, " I Line      = [0x%x]\n",
47826947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_ILINE));
47926947304SEvan Yan 	cmn_err(CE_CONT, " I Pin       = [0x%x]\n",
48026947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_IPIN));
48126947304SEvan Yan 	cmn_err(CE_CONT, " Max Grant   = [0x%x]\n",
48226947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
48326947304SEvan Yan 	cmn_err(CE_CONT, " Max Latent  = [0x%x]\n",
48426947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
48526947304SEvan Yan }
48626947304SEvan Yan 
48726947304SEvan Yan static void
48826947304SEvan Yan pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
48926947304SEvan Yan {
49026947304SEvan Yan 	if ((pcicfg_debug & 1) == 0)
49126947304SEvan Yan 		return;
49226947304SEvan Yan 
49326947304SEvan Yan 	pcicfg_dump_common_config(config_handle);
49426947304SEvan Yan 
49526947304SEvan Yan 	cmn_err(CE_CONT, "........................................\n");
49626947304SEvan Yan 
49726947304SEvan Yan 	cmn_err(CE_CONT, " Pri Bus     = [0x%x]\n",
49826947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
49926947304SEvan Yan 	cmn_err(CE_CONT, " Sec Bus     = [0x%x]\n",
50026947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
50126947304SEvan Yan 	cmn_err(CE_CONT, " Sub Bus     = [0x%x]\n",
50226947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
50326947304SEvan Yan 	cmn_err(CE_CONT, " Latency     = [0x%x]\n",
50426947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
50526947304SEvan Yan 	cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n",
50626947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
50726947304SEvan Yan 	cmn_err(CE_CONT, " I/O Lim LO  = [0x%x]\n",
50826947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
50926947304SEvan Yan 	cmn_err(CE_CONT, " Sec. Status = [0x%x]\n",
51026947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
51126947304SEvan Yan 	cmn_err(CE_CONT, " Mem Base    = [0x%x]\n",
51226947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
51326947304SEvan Yan 	cmn_err(CE_CONT, " Mem Limit   = [0x%x]\n",
51426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
51526947304SEvan Yan 	cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n",
51626947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
51726947304SEvan Yan 	cmn_err(CE_CONT, " PF Mem Lim  = [0x%x]\n",
51826947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
51926947304SEvan Yan 	cmn_err(CE_CONT, " PF Base HI  = [0x%x]\n",
52026947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
52126947304SEvan Yan 	cmn_err(CE_CONT, " PF Lim  HI  = [0x%x]\n",
52226947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
52326947304SEvan Yan 	cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n",
52426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
52526947304SEvan Yan 	cmn_err(CE_CONT, " I/O Lim HI  = [0x%x]\n",
52626947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
52726947304SEvan Yan 	cmn_err(CE_CONT, " ROM addr    = [0x%x]\n",
52826947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_ROM));
52926947304SEvan Yan 	cmn_err(CE_CONT, " Intr Line   = [0x%x]\n",
53026947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
53126947304SEvan Yan 	cmn_err(CE_CONT, " Intr Pin    = [0x%x]\n",
53226947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
53326947304SEvan Yan 	cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n",
53426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
53526947304SEvan Yan }
53626947304SEvan Yan 
53726947304SEvan Yan #endif
53826947304SEvan Yan 
53926947304SEvan Yan 
54026947304SEvan Yan int
54126947304SEvan Yan _init()
54226947304SEvan Yan {
54326947304SEvan Yan 	DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n");
54426947304SEvan Yan 
54526947304SEvan Yan 	mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
54626947304SEvan Yan 	return (mod_install(&modlinkage));
54726947304SEvan Yan }
54826947304SEvan Yan 
54926947304SEvan Yan int
55026947304SEvan Yan _fini(void)
55126947304SEvan Yan {
55226947304SEvan Yan 	int error;
55326947304SEvan Yan 
55426947304SEvan Yan 	error = mod_remove(&modlinkage);
55526947304SEvan Yan 	if (error != 0) {
55626947304SEvan Yan 		return (error);
55726947304SEvan Yan 	}
55826947304SEvan Yan 	mutex_destroy(&pcicfg_list_mutex);
55926947304SEvan Yan 	return (0);
56026947304SEvan Yan }
56126947304SEvan Yan 
56226947304SEvan Yan int
56326947304SEvan Yan _info(modinfop)
56426947304SEvan Yan struct modinfo *modinfop;
56526947304SEvan Yan {
56626947304SEvan Yan 	return (mod_info(&modlinkage, modinfop));
56726947304SEvan Yan }
56826947304SEvan Yan 
56926947304SEvan Yan /*ARGSUSED*/
57026947304SEvan Yan static uint8_t
57126947304SEvan Yan pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
57226947304SEvan Yan {
57326947304SEvan Yan 	uint8_t num_slots = 0;
57426947304SEvan Yan 	uint16_t cap_ptr;
57526947304SEvan Yan 
57626947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG,
57726947304SEvan Yan 	    &cap_ptr)) == DDI_SUCCESS) {
57826947304SEvan Yan 		uint32_t config;
57926947304SEvan Yan 
58026947304SEvan Yan 		PCI_CAP_PUT8(handle, NULL, cap_ptr, PCI_HP_DWORD_SELECT_OFF,
58126947304SEvan Yan 		    PCI_HP_SLOT_CONFIGURATION_REG);
58226947304SEvan Yan 		config = PCI_CAP_GET32(handle, NULL, cap_ptr,
58326947304SEvan Yan 		    PCI_HP_DWORD_DATA_OFF);
58426947304SEvan Yan 		num_slots = config & 0x1F;
58526947304SEvan Yan 	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr))
58626947304SEvan Yan 	    == DDI_SUCCESS) {
58726947304SEvan Yan 		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL,
58826947304SEvan Yan 		    cap_ptr, PCI_CAP_ID_REGS_OFF);
58926947304SEvan Yan 
59026947304SEvan Yan 		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
59126947304SEvan Yan 	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
59226947304SEvan Yan 	    == DDI_SUCCESS) {
59326947304SEvan Yan 		int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr,
59426947304SEvan Yan 		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
59526947304SEvan Yan 
59626947304SEvan Yan 		if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) &&
59726947304SEvan Yan 		    (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP)
59826947304SEvan Yan 		    & PCIE_PCIECAP_SLOT_IMPL))
59926947304SEvan Yan 				num_slots = 1;
60026947304SEvan Yan 	}
60126947304SEvan Yan 
60226947304SEvan Yan 	DEBUG3("%s#%d has %d slots",
60326947304SEvan Yan 	    ddi_get_name(dip), ddi_get_instance(dip), num_slots);
60426947304SEvan Yan 
60526947304SEvan Yan 	return (num_slots);
60626947304SEvan Yan }
60726947304SEvan Yan 
60826947304SEvan Yan /*ARGSUSED*/
60926947304SEvan Yan static uint8_t
61026947304SEvan Yan pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle)
61126947304SEvan Yan {
61226947304SEvan Yan 	uint16_t cap_ptr;
61326947304SEvan Yan 
61426947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) !=
61526947304SEvan Yan 	    DDI_FAILURE) {
61626947304SEvan Yan 
61726947304SEvan Yan 		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2);
61826947304SEvan Yan 		if (PCI_CAPSLOT_FIC(esr_reg))
61926947304SEvan Yan 			return (B_TRUE);
62026947304SEvan Yan 	}
62126947304SEvan Yan 	return (B_FALSE);
62226947304SEvan Yan }
62326947304SEvan Yan 
62426947304SEvan Yan /*ARGSUSED*/
62526947304SEvan Yan static int
62626947304SEvan Yan pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs)
62726947304SEvan Yan {
62826947304SEvan Yan 	/* get parent device's device_type property */
62926947304SEvan Yan 	char *device_type;
63026947304SEvan Yan 	int rc = DDI_FAILURE;
63126947304SEvan Yan 	dev_info_t *pdip = ddi_get_parent(dip);
63226947304SEvan Yan 
63326947304SEvan Yan 	regs->pcie_dev = 0;
63426947304SEvan Yan 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
63526947304SEvan Yan 	    DDI_PROP_DONTPASS, "device_type", &device_type)
63626947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
63726947304SEvan Yan 		DEBUG2("device_type property missing for %s#%d",
63826947304SEvan Yan 		    ddi_get_name(pdip), ddi_get_instance(pdip));
63926947304SEvan Yan 		return (DDI_FAILURE);
64026947304SEvan Yan 	}
64126947304SEvan Yan 	switch (bus_type) {
64226947304SEvan Yan 		case PCICFG_DEVICE_TYPE_PCIE:
64326947304SEvan Yan 			if (strcmp(device_type, "pciex") == 0) {
64426947304SEvan Yan 				rc = DDI_SUCCESS;
64526947304SEvan Yan 				regs->pcie_dev = 1;
64626947304SEvan Yan 			}
64726947304SEvan Yan 			break;
64826947304SEvan Yan 		case PCICFG_DEVICE_TYPE_PCI:
64926947304SEvan Yan 			if (strcmp(device_type, "pci") == 0)
65026947304SEvan Yan 				rc = DDI_SUCCESS;
65126947304SEvan Yan 			break;
65226947304SEvan Yan 		default:
65326947304SEvan Yan 			break;
65426947304SEvan Yan 	}
65526947304SEvan Yan 	ddi_prop_free(device_type);
65626947304SEvan Yan 	return (rc);
65726947304SEvan Yan }
65826947304SEvan Yan 
65926947304SEvan Yan /*ARGSUSED*/
66026947304SEvan Yan static int
66126947304SEvan Yan pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
66226947304SEvan Yan {
66326947304SEvan Yan 	int port_type = -1;
66426947304SEvan Yan 	uint16_t cap_ptr;
66526947304SEvan Yan 
66626947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
66726947304SEvan Yan 	    DDI_FAILURE)
66826947304SEvan Yan 		port_type = PCI_CAP_GET16(handle, NULL,
66926947304SEvan Yan 		    cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
67026947304SEvan Yan 
67126947304SEvan Yan 	return (port_type);
67226947304SEvan Yan }
67326947304SEvan Yan 
67426947304SEvan Yan static int
67526947304SEvan Yan pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
67626947304SEvan Yan {
67726947304SEvan Yan 	int port_type = pcicfg_pcie_port_type(dip, handle);
67826947304SEvan Yan 
67926947304SEvan Yan 	DEBUG1("device port_type = %x\n", port_type);
68026947304SEvan Yan 	/* No PCIe CAP regs, we are not PCIe device_type */
68126947304SEvan Yan 	if (port_type < 0)
68226947304SEvan Yan 		return (DDI_FAILURE);
68326947304SEvan Yan 
68426947304SEvan Yan 	/* check for all PCIe device_types */
68526947304SEvan Yan 	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
68626947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
68726947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
68826947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
68926947304SEvan Yan 		return (DDI_SUCCESS);
69026947304SEvan Yan 
69126947304SEvan Yan 	return (DDI_FAILURE);
69226947304SEvan Yan 
69326947304SEvan Yan }
69426947304SEvan Yan 
69526947304SEvan Yan /*
69626947304SEvan Yan  * In the following functions ndi_devi_enter() without holding the
69726947304SEvan Yan  * parent dip is sufficient. This is because  pci dr is driven through
69826947304SEvan Yan  * opens on the nexus which is in the device tree path above the node
69926947304SEvan Yan  * being operated on, and implicitly held due to the open.
70026947304SEvan Yan  */
70126947304SEvan Yan 
70226947304SEvan Yan /*
70326947304SEvan Yan  * This entry point is called to configure a device (and
70426947304SEvan Yan  * all its children) on the given bus. It is called when
70526947304SEvan Yan  * a new device is added to the PCI domain.  This routine
70626947304SEvan Yan  * will create the device tree and program the devices
70726947304SEvan Yan  * registers.
70826947304SEvan Yan  */
70926947304SEvan Yan 
71026947304SEvan Yan int
71126947304SEvan Yan pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
71226947304SEvan Yan     pcicfg_flags_t flags)
71326947304SEvan Yan {
71426947304SEvan Yan 	uint_t bus;
71526947304SEvan Yan 	int len;
71626947304SEvan Yan 	int func;
71726947304SEvan Yan 	int trans_device;
71826947304SEvan Yan 	dev_info_t *new_device;
71926947304SEvan Yan 	pcicfg_bus_range_t pci_bus_range;
72026947304SEvan Yan 	int rv;
72126947304SEvan Yan 	int circ;
72226947304SEvan Yan 	uint_t highest_bus = 0;
72326947304SEvan Yan 	int ari_mode = B_FALSE;
72426947304SEvan Yan 	int max_function = PCICFG_MAX_FUNCTION;
725c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
72626947304SEvan Yan 
72726947304SEvan Yan 	if (flags == PCICFG_FLAG_ENABLE_ARI)
72826947304SEvan Yan 		return (pcicfg_ari_configure(devi));
72926947304SEvan Yan 
73026947304SEvan Yan 	/*
73126947304SEvan Yan 	 * Start probing at the device specified in "device" on the
73226947304SEvan Yan 	 * "bus" specified.
73326947304SEvan Yan 	 */
73426947304SEvan Yan 	len = sizeof (pcicfg_bus_range_t);
73526947304SEvan Yan 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
73626947304SEvan Yan 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
73726947304SEvan Yan 		DEBUG0("no bus-range property\n");
73826947304SEvan Yan 		return (PCICFG_FAILURE);
73926947304SEvan Yan 	}
74026947304SEvan Yan 
74126947304SEvan Yan 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
74226947304SEvan Yan 
743c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
744c0da6274SZhi-Jun Robin Fu 
74526947304SEvan Yan 	ndi_devi_enter(devi, &circ);
74626947304SEvan Yan 	for (func = 0; func < max_function; ) {
74726947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
74826947304SEvan Yan 			goto next;
74926947304SEvan Yan 
75026947304SEvan Yan 		if (ari_mode)
75126947304SEvan Yan 			trans_device = func >> 3;
75226947304SEvan Yan 		else
75326947304SEvan Yan 			trans_device = device;
75426947304SEvan Yan 
75526947304SEvan Yan 		DEBUG3("Configuring [0x%x][0x%x][0x%x]\n",
75626947304SEvan Yan 		    bus, trans_device, func & 7);
75726947304SEvan Yan 
75826947304SEvan Yan 		/*
75926947304SEvan Yan 		 * Try executing fcode if available.
76026947304SEvan Yan 		 */
76126947304SEvan Yan 		switch (rv = pcicfg_fcode_probe(devi, bus, trans_device,
762c0da6274SZhi-Jun Robin Fu 		    func & 7, &highest_bus, flags, is_pcie)) {
76326947304SEvan Yan 			case PCICFG_FAILURE:
76426947304SEvan Yan 				DEBUG2("configure failed: "
76526947304SEvan Yan 				    "bus [0x%x] device [0x%x]\n",
76626947304SEvan Yan 				    bus, trans_device);
76726947304SEvan Yan 				break;
76826947304SEvan Yan 			case PCICFG_NODEVICE:
76926947304SEvan Yan 				DEBUG3("no device : bus "
77026947304SEvan Yan 				    "[0x%x] slot [0x%x] func [0x%x]\n",
77126947304SEvan Yan 				    bus, trans_device, func & 7);
772*7f59ab1cSAlan Adamson, SD OSSD 
773*7f59ab1cSAlan Adamson, SD OSSD 				/*
774*7f59ab1cSAlan Adamson, SD OSSD 				 * When walking the list of ARI functions
775*7f59ab1cSAlan Adamson, SD OSSD 				 * we don't expect to see a non-present
776*7f59ab1cSAlan Adamson, SD OSSD 				 * function, so we will stop walking
777*7f59ab1cSAlan Adamson, SD OSSD 				 * the function list.
778*7f59ab1cSAlan Adamson, SD OSSD 				 */
779*7f59ab1cSAlan Adamson, SD OSSD 				if (ari_mode == B_TRUE)
780*7f59ab1cSAlan Adamson, SD OSSD 					break;
781*7f59ab1cSAlan Adamson, SD OSSD 
78226947304SEvan Yan 				if (func)
78326947304SEvan Yan 					goto next;
78426947304SEvan Yan 				break;
78526947304SEvan Yan 			default:
78626947304SEvan Yan 				DEBUG3("configure: bus => [%d] "
78726947304SEvan Yan 				    "slot => [%d] func => [%d]\n",
78826947304SEvan Yan 				    bus, trans_device, func & 7);
78926947304SEvan Yan 				break;
79026947304SEvan Yan 		}
79126947304SEvan Yan 
79226947304SEvan Yan 		if (rv != PCICFG_SUCCESS)
79326947304SEvan Yan 			break;
79426947304SEvan Yan 
79526947304SEvan Yan 		if ((new_device = pcicfg_devi_find(devi,
79626947304SEvan Yan 		    trans_device, (func & 7))) == NULL) {
79726947304SEvan Yan 			DEBUG0("Did'nt find device node just created\n");
79826947304SEvan Yan 			goto cleanup;
79926947304SEvan Yan 		}
80026947304SEvan Yan 
80126947304SEvan Yan next:
80226947304SEvan Yan 		/*
80326947304SEvan Yan 		 * Determine if ARI Forwarding should be enabled.
80426947304SEvan Yan 		 */
80526947304SEvan Yan 		if (func == 0) {
80626947304SEvan Yan 			if ((pcie_ari_supported(devi)
80726947304SEvan Yan 			    == PCIE_ARI_FORW_SUPPORTED) &&
80826947304SEvan Yan 			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
80926947304SEvan Yan 				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
81026947304SEvan Yan 					(void) ddi_prop_create(DDI_DEV_T_NONE,
81126947304SEvan Yan 					    devi,  DDI_PROP_CANSLEEP,
81226947304SEvan Yan 					    "ari-enabled", NULL, 0);
81326947304SEvan Yan 
81426947304SEvan Yan 					ari_mode = B_TRUE;
81526947304SEvan Yan 					max_function = PCICFG_MAX_ARI_FUNCTION;
81626947304SEvan Yan 				}
81726947304SEvan Yan 			}
81826947304SEvan Yan 		}
81926947304SEvan Yan 
82026947304SEvan Yan 		if (ari_mode == B_TRUE) {
82126947304SEvan Yan 			int next_function;
82226947304SEvan Yan 
82326947304SEvan Yan 			DEBUG0("Next Function - ARI Device\n");
82426947304SEvan Yan 			if (pcie_ari_get_next_function(new_device,
82526947304SEvan Yan 			    &next_function) != DDI_SUCCESS)
82626947304SEvan Yan 				goto cleanup;
82726947304SEvan Yan 
82826947304SEvan Yan 			/*
82926947304SEvan Yan 			 * Check if there are more fucntions to probe.
83026947304SEvan Yan 			 */
83126947304SEvan Yan 			if (next_function == 0) {
83226947304SEvan Yan 				DEBUG0("Next Function - "
83326947304SEvan Yan 				    "No more ARI Functions\n");
83426947304SEvan Yan 				break;
83526947304SEvan Yan 			}
83626947304SEvan Yan 			func = next_function;
83726947304SEvan Yan 		} else {
83826947304SEvan Yan 			func++;
83926947304SEvan Yan 		}
84026947304SEvan Yan 
84126947304SEvan Yan 		DEBUG1("Next Function - %x\n", func);
84226947304SEvan Yan 	}
84326947304SEvan Yan 
84426947304SEvan Yan 	ndi_devi_exit(devi, circ);
84526947304SEvan Yan 
84626947304SEvan Yan 	if (func == 0)
84726947304SEvan Yan 		return (PCICFG_FAILURE);	/* probe failed */
84826947304SEvan Yan 	else
84926947304SEvan Yan 		return (PCICFG_SUCCESS);
85026947304SEvan Yan 
85126947304SEvan Yan cleanup:
85226947304SEvan Yan 	/*
85326947304SEvan Yan 	 * Clean up a partially created "probe state" tree.
85426947304SEvan Yan 	 * There are no resources allocated to the in the
85526947304SEvan Yan 	 * probe state.
85626947304SEvan Yan 	 */
85726947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
85826947304SEvan Yan 		max_function = PCICFG_MAX_ARI_FUNCTION;
85926947304SEvan Yan 	else
86026947304SEvan Yan 		max_function = PCICFG_MAX_FUNCTION;
86126947304SEvan Yan 
86226947304SEvan Yan 	for (func = 0; func < max_function; func++) {
86326947304SEvan Yan 
86426947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
86526947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
86626947304SEvan Yan 		else
86726947304SEvan Yan 			trans_device = device;
86826947304SEvan Yan 
86926947304SEvan Yan 		if ((new_device = pcicfg_devi_find(devi,
87026947304SEvan Yan 		    trans_device, (func & 0x7))) == NULL) {
87126947304SEvan Yan 			DEBUG0("No more devices to clean up\n");
87226947304SEvan Yan 			continue;
87326947304SEvan Yan 		}
87426947304SEvan Yan 
87526947304SEvan Yan 		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
87626947304SEvan Yan 		    trans_device, func & 7);
87726947304SEvan Yan 		/*
87826947304SEvan Yan 		 * If this was a bridge device it will have a
87926947304SEvan Yan 		 * probe handle - if not, no harm in calling this.
88026947304SEvan Yan 		 */
88126947304SEvan Yan 		(void) pcicfg_destroy_phdl(new_device);
882c0da6274SZhi-Jun Robin Fu 
883c0da6274SZhi-Jun Robin Fu 		if (is_pcie) {
884c0da6274SZhi-Jun Robin Fu 			/*
885c0da6274SZhi-Jun Robin Fu 			 * Free bus_t structure
886c0da6274SZhi-Jun Robin Fu 			 */
887c0da6274SZhi-Jun Robin Fu 			if (ddi_get_child(new_device) != NULL)
888c0da6274SZhi-Jun Robin Fu 				pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
889c0da6274SZhi-Jun Robin Fu 
890c0da6274SZhi-Jun Robin Fu 			pcie_fini_bus(new_device, PCIE_BUS_ALL);
891c0da6274SZhi-Jun Robin Fu 		}
89226947304SEvan Yan 		/*
89326947304SEvan Yan 		 * This will free up the node
89426947304SEvan Yan 		 */
89526947304SEvan Yan 		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
89626947304SEvan Yan 	}
89726947304SEvan Yan 	ndi_devi_exit(devi, circ);
89826947304SEvan Yan 
89926947304SEvan Yan 	return (PCICFG_FAILURE);
90026947304SEvan Yan }
90126947304SEvan Yan 
90226947304SEvan Yan /*
90326947304SEvan Yan  * configure the child nodes of ntbridge. new_device points to ntbridge itself
90426947304SEvan Yan  */
90526947304SEvan Yan /*ARGSUSED*/
90626947304SEvan Yan static uint_t
90726947304SEvan Yan pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
90826947304SEvan Yan {
90926947304SEvan Yan 	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
91026947304SEvan Yan 	int			devno;
91126947304SEvan Yan 	dev_info_t		*new_ntbridgechild;
91226947304SEvan Yan 	ddi_acc_handle_t	config_handle;
91326947304SEvan Yan 	uint16_t		vid;
91426947304SEvan Yan 	uint64_t		next_bus;
91526947304SEvan Yan 	uint64_t		blen;
91626947304SEvan Yan 	ndi_ra_request_t	req;
91726947304SEvan Yan 	uint8_t			pcie_device_type = 0;
91826947304SEvan Yan 
91926947304SEvan Yan 	/*
92026947304SEvan Yan 	 * If we need to do indirect config, lets create a property here
92126947304SEvan Yan 	 * to let the child conf map routine know that it has to
92226947304SEvan Yan 	 * go through the DDI calls, and not assume the devices are
92326947304SEvan Yan 	 * mapped directly under the host.
92426947304SEvan Yan 	 */
92526947304SEvan Yan 	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
92626947304SEvan Yan 	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
92726947304SEvan Yan 	    != DDI_SUCCESS) {
92826947304SEvan Yan 
92926947304SEvan Yan 		DEBUG0("Cannot create indirect conf map property.\n");
93026947304SEvan Yan 		return ((uint_t)PCICFG_FAILURE);
93126947304SEvan Yan 	}
93226947304SEvan Yan 	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
93326947304SEvan Yan 		return ((uint_t)PCICFG_FAILURE);
93426947304SEvan Yan 	/* check if we are PCIe device */
93526947304SEvan Yan 	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS)
93626947304SEvan Yan 		pcie_device_type = 1;
93726947304SEvan Yan 	pci_config_teardown(&config_handle);
93826947304SEvan Yan 
93926947304SEvan Yan 	/* create Bus node properties for ntbridge. */
94026947304SEvan Yan 	if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) !=
94126947304SEvan Yan 	    PCICFG_SUCCESS) {
94226947304SEvan Yan 		DEBUG0("Failed to set busnode props\n");
94326947304SEvan Yan 		return (rc);
94426947304SEvan Yan 	}
94526947304SEvan Yan 
94626947304SEvan Yan 	/* For now: Lets only support one layer of child */
94726947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
94826947304SEvan Yan 	req.ra_len = 1;
94926947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(new_device), &req,
95026947304SEvan Yan 	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
95126947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
95226947304SEvan Yan 		DEBUG0("ntbridge: Failed to get a bus number\n");
95326947304SEvan Yan 		return (rc);
95426947304SEvan Yan 	}
95526947304SEvan Yan 
95626947304SEvan Yan 	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
95726947304SEvan Yan 
95826947304SEvan Yan 	/*
95926947304SEvan Yan 	 * Following will change, as we detect more bridges
96026947304SEvan Yan 	 * on the way.
96126947304SEvan Yan 	 */
96226947304SEvan Yan 	bus_range[0] = (int)next_bus;
96326947304SEvan Yan 	bus_range[1] = (int)next_bus;
96426947304SEvan Yan 
96526947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device,
96626947304SEvan Yan 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
96726947304SEvan Yan 		DEBUG0("Cannot set ntbridge bus-range property");
96826947304SEvan Yan 		return (rc);
96926947304SEvan Yan 	}
97026947304SEvan Yan 
97126947304SEvan Yan 	/*
97226947304SEvan Yan 	 * The other interface (away from the host) will be
97326947304SEvan Yan 	 * initialized by the nexus driver when it loads.
97426947304SEvan Yan 	 * We just have to set the registers and the nexus driver
97526947304SEvan Yan 	 * figures out the rest.
97626947304SEvan Yan 	 */
97726947304SEvan Yan 
97826947304SEvan Yan 	/*
97926947304SEvan Yan 	 * finally, lets load and attach the driver
98026947304SEvan Yan 	 * before configuring children of ntbridge.
98126947304SEvan Yan 	 */
98226947304SEvan Yan 	rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG);
98326947304SEvan Yan 	if (rc != NDI_SUCCESS) {
98426947304SEvan Yan 		cmn_err(CE_WARN,
98526947304SEvan Yan 		    "pcicfg: Fail: can\'t load non-transparent bridge \
98626947304SEvan Yan 		    driver.\n");
98726947304SEvan Yan 		rc = PCICFG_FAILURE;
98826947304SEvan Yan 		return (rc);
98926947304SEvan Yan 	}
99026947304SEvan Yan 	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
99126947304SEvan Yan 
99226947304SEvan Yan 	/* Now set aside pci resources for our children. */
99326947304SEvan Yan 	if (pcicfg_ntbridge_allocate_resources(new_device) !=
99426947304SEvan Yan 	    PCICFG_SUCCESS) {
99526947304SEvan Yan 		max_devs = 0;
99626947304SEvan Yan 		rc = PCICFG_FAILURE;
99726947304SEvan Yan 	} else
99826947304SEvan Yan 		max_devs = PCICFG_MAX_DEVICE;
99926947304SEvan Yan 
100026947304SEvan Yan 	/* Probe devices on 2nd bus */
100126947304SEvan Yan 	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
100226947304SEvan Yan 
100326947304SEvan Yan 		if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
100426947304SEvan Yan 		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild)
100526947304SEvan Yan 		    != NDI_SUCCESS) {
100626947304SEvan Yan 
100726947304SEvan Yan 			DEBUG0("pcicfg: Failed to alloc test node\n");
100826947304SEvan Yan 			rc = PCICFG_FAILURE;
100926947304SEvan Yan 			break;
101026947304SEvan Yan 		}
101126947304SEvan Yan 
101226947304SEvan Yan 		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
101326947304SEvan Yan 		    != DDI_PROP_SUCCESS) {
101426947304SEvan Yan 			cmn_err(CE_WARN,
101526947304SEvan Yan 			    "Failed to add conf reg for ntbridge child.\n");
101626947304SEvan Yan 			(void) ndi_devi_free(new_ntbridgechild);
101726947304SEvan Yan 			rc = PCICFG_FAILURE;
101826947304SEvan Yan 			break;
101926947304SEvan Yan 		}
102026947304SEvan Yan 
102126947304SEvan Yan 		if ((rc = pci_config_setup(new_ntbridgechild,
102226947304SEvan Yan 		    &config_handle)) != PCICFG_SUCCESS) {
102326947304SEvan Yan 			cmn_err(CE_WARN,
102426947304SEvan Yan 			    "Cannot map ntbridge child %x\n", devno);
102526947304SEvan Yan 			(void) ndi_devi_free(new_ntbridgechild);
102626947304SEvan Yan 			rc = PCICFG_FAILURE;
102726947304SEvan Yan 			break;
102826947304SEvan Yan 		}
102926947304SEvan Yan 
103026947304SEvan Yan 		/*
103126947304SEvan Yan 		 * See if there is any PCI HW at this location
103226947304SEvan Yan 		 * by reading the Vendor ID.  If it returns with 0xffff
103326947304SEvan Yan 		 * then there is no hardware at this location.
103426947304SEvan Yan 		 */
103526947304SEvan Yan 		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
103626947304SEvan Yan 
103726947304SEvan Yan 		pci_config_teardown(&config_handle);
103826947304SEvan Yan 		(void) ndi_devi_free(new_ntbridgechild);
103926947304SEvan Yan 		if (vid	== 0xffff)
104026947304SEvan Yan 			continue;
104126947304SEvan Yan 
104226947304SEvan Yan 		/* Lets fake attachments points for each child, */
104326947304SEvan Yan 		if (pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0)
104426947304SEvan Yan 		    != PCICFG_SUCCESS) {
104526947304SEvan Yan 			int old_dev = pcicfg_start_devno;
104626947304SEvan Yan 
104726947304SEvan Yan 			cmn_err(CE_WARN,
104826947304SEvan Yan 			"Error configuring ntbridge child dev=%d\n", devno);
104926947304SEvan Yan 
105026947304SEvan Yan 			rc = PCICFG_FAILURE;
105126947304SEvan Yan 			while (old_dev != devno) {
105226947304SEvan Yan 				if (pcicfg_ntbridge_unconfigure_child(
105326947304SEvan Yan 				    new_device, old_dev) == PCICFG_FAILURE)
105426947304SEvan Yan 
105526947304SEvan Yan 					cmn_err(CE_WARN,
105626947304SEvan Yan 					    "Unconfig Error ntbridge child "
105726947304SEvan Yan 					    "dev=%d\n", old_dev);
105826947304SEvan Yan 				old_dev++;
105926947304SEvan Yan 			}
106026947304SEvan Yan 			break;
106126947304SEvan Yan 		}
106226947304SEvan Yan 	} /* devno loop */
106326947304SEvan Yan 	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
106426947304SEvan Yan 
106526947304SEvan Yan 	if (rc != PCICFG_FAILURE)
106626947304SEvan Yan 		rc = pcicfg_ntbridge_configure_done(new_device);
106726947304SEvan Yan 	else {
106826947304SEvan Yan 		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
106926947304SEvan Yan 		uint_t			*bus;
107026947304SEvan Yan 		int			k;
107126947304SEvan Yan 
107226947304SEvan Yan 		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
107326947304SEvan Yan 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
107426947304SEvan Yan 		    &k) != DDI_PROP_SUCCESS) {
107526947304SEvan Yan 			DEBUG0("Failed to read bus-range property\n");
107626947304SEvan Yan 			rc = PCICFG_FAILURE;
107726947304SEvan Yan 			return (rc);
107826947304SEvan Yan 		}
107926947304SEvan Yan 
108026947304SEvan Yan 		DEBUG2("Need to free bus [%d] range [%d]\n",
108126947304SEvan Yan 		    bus[0], bus[1] - bus[0] + 1);
108226947304SEvan Yan 
108326947304SEvan Yan 		if (ndi_ra_free(ddi_get_parent(new_device),
108426947304SEvan Yan 		    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
108526947304SEvan Yan 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
108626947304SEvan Yan 			DEBUG0("Failed to free a bus number\n");
108726947304SEvan Yan 			rc = PCICFG_FAILURE;
108826947304SEvan Yan 			/*
108926947304SEvan Yan 			 * Don't forget to free up memory from ddi_getlongprop
109026947304SEvan Yan 			 */
109126947304SEvan Yan 			kmem_free((caddr_t)bus, k);
109226947304SEvan Yan 
109326947304SEvan Yan 			return (rc);
109426947304SEvan Yan 		}
109526947304SEvan Yan 
109626947304SEvan Yan 		/*
109726947304SEvan Yan 		 * Since no memory allocations are done for non transparent
109826947304SEvan Yan 		 * bridges (but instead we just set the handle with the
109926947304SEvan Yan 		 * already allocated memory, we just need to reset the
110026947304SEvan Yan 		 * following values before calling the destroy_phdl()
110126947304SEvan Yan 		 * function next, otherwise the it will try to free
110226947304SEvan Yan 		 * memory allocated as in case of a transparent bridge.
110326947304SEvan Yan 		 */
110426947304SEvan Yan 		entry->memory_len = 0;
110526947304SEvan Yan 		entry->io_len = 0;
110626947304SEvan Yan 		/* the following will free hole data. */
110726947304SEvan Yan 		(void) pcicfg_destroy_phdl(new_device);
110826947304SEvan Yan 		/*
110926947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
111026947304SEvan Yan 		 */
111126947304SEvan Yan 		kmem_free((caddr_t)bus, k);
111226947304SEvan Yan 	}
111326947304SEvan Yan 
111426947304SEvan Yan 	/*
111526947304SEvan Yan 	 * Unload driver just in case child configure failed!
111626947304SEvan Yan 	 */
111726947304SEvan Yan 	rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT);
111826947304SEvan Yan 	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
111926947304SEvan Yan 	if (rc1 != NDI_SUCCESS) {
112026947304SEvan Yan 		cmn_err(CE_WARN,
112126947304SEvan Yan 		    "pcicfg: can\'t unload ntbridge driver children.\n");
112226947304SEvan Yan 		rc = PCICFG_FAILURE;
112326947304SEvan Yan 	}
112426947304SEvan Yan 
112526947304SEvan Yan 	return (rc);
112626947304SEvan Yan }
112726947304SEvan Yan 
112826947304SEvan Yan static int
112926947304SEvan Yan pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
113026947304SEvan Yan {
113126947304SEvan Yan 	pcicfg_phdl_t		*phdl;
113226947304SEvan Yan 	ndi_ra_request_t	*mem_request;
113326947304SEvan Yan 	ndi_ra_request_t	*io_request;
113426947304SEvan Yan 	uint64_t		boundbase, boundlen;
113526947304SEvan Yan 
113626947304SEvan Yan 	phdl = pcicfg_find_phdl(dip);
113726947304SEvan Yan 	ASSERT(phdl);
113826947304SEvan Yan 
113926947304SEvan Yan 	mem_request = &phdl->mem_req;
114026947304SEvan Yan 	io_request  = &phdl->io_req;
114126947304SEvan Yan 
114226947304SEvan Yan 	phdl->error = PCICFG_SUCCESS;
114326947304SEvan Yan 
114426947304SEvan Yan 	/* Set Memory space handle for ntbridge */
114526947304SEvan Yan 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
114626947304SEvan Yan 	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
114726947304SEvan Yan 		cmn_err(CE_WARN,
114826947304SEvan Yan 		    "ntbridge: Mem resource information failure\n");
114926947304SEvan Yan 		phdl->memory_len  = 0;
115026947304SEvan Yan 		return (PCICFG_FAILURE);
115126947304SEvan Yan 	}
115226947304SEvan Yan 	mem_request->ra_boundbase = boundbase;
115326947304SEvan Yan 	mem_request->ra_boundlen = boundbase + boundlen;
115426947304SEvan Yan 	mem_request->ra_len = boundlen;
115526947304SEvan Yan 	mem_request->ra_align_mask =
115626947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
115726947304SEvan Yan 	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
115826947304SEvan Yan 
115926947304SEvan Yan 	/*
116026947304SEvan Yan 	 * mem_request->ra_len =
116126947304SEvan Yan 	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
116226947304SEvan Yan 	 */
116326947304SEvan Yan 
116426947304SEvan Yan 	phdl->memory_base = phdl->memory_last = boundbase;
116526947304SEvan Yan 	phdl->memory_len  = boundlen;
116626947304SEvan Yan 	phdl->mem_hole.start = phdl->memory_base;
116726947304SEvan Yan 	phdl->mem_hole.len = mem_request->ra_len;
116826947304SEvan Yan 	phdl->mem_hole.next = (hole_t *)NULL;
116926947304SEvan Yan 
117026947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
117126947304SEvan Yan 	    boundlen, mem_request->ra_len);
117226947304SEvan Yan 
117326947304SEvan Yan 	/* set up a memory resource map for NT bridge */
117426947304SEvan Yan 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
117526947304SEvan Yan 		DEBUG0("Can not setup ntbridge memory resource map\n");
117626947304SEvan Yan 		return (PCICFG_FAILURE);
117726947304SEvan Yan 	}
117826947304SEvan Yan 	/* initialize the memory map */
117926947304SEvan Yan 	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM,
118026947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
118126947304SEvan Yan 		DEBUG0("Can not initalize ntbridge memory resource map\n");
118226947304SEvan Yan 		return (PCICFG_FAILURE);
118326947304SEvan Yan 	}
118426947304SEvan Yan 	/* Set IO space handle for ntbridge */
118526947304SEvan Yan 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
118626947304SEvan Yan 	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
118726947304SEvan Yan 		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
118826947304SEvan Yan 		phdl->io_len  = 0;
118926947304SEvan Yan 		return (PCICFG_FAILURE);
119026947304SEvan Yan 	}
119126947304SEvan Yan 	io_request->ra_len = boundlen;
119226947304SEvan Yan 	io_request->ra_align_mask =
119326947304SEvan Yan 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
119426947304SEvan Yan 	io_request->ra_boundbase = boundbase;
119526947304SEvan Yan 	io_request->ra_boundlen = boundbase + boundlen;
119626947304SEvan Yan 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
119726947304SEvan Yan 
119826947304SEvan Yan 	/*
119926947304SEvan Yan 	 * io_request->ra_len =
120026947304SEvan Yan 	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
120126947304SEvan Yan 	 */
120226947304SEvan Yan 
120326947304SEvan Yan 	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
120426947304SEvan Yan 	phdl->io_len  = (uint32_t)boundlen;
120526947304SEvan Yan 	phdl->io_hole.start = phdl->io_base;
120626947304SEvan Yan 	phdl->io_hole.len = io_request->ra_len;
120726947304SEvan Yan 	phdl->io_hole.next = (hole_t *)NULL;
120826947304SEvan Yan 
120926947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
121026947304SEvan Yan 	    boundlen, io_request->ra_len);
121126947304SEvan Yan 
121226947304SEvan Yan 	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
121326947304SEvan Yan 	    phdl->memory_base, phdl->memory_len);
121426947304SEvan Yan 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
121526947304SEvan Yan 	    phdl->io_base, phdl->io_len);
121626947304SEvan Yan 
121726947304SEvan Yan 	/* set up a IO resource map for NT bridge */
121826947304SEvan Yan 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
121926947304SEvan Yan 		DEBUG0("Can not setup ntbridge memory resource map\n");
122026947304SEvan Yan 		return (PCICFG_FAILURE);
122126947304SEvan Yan 	}
122226947304SEvan Yan 	/* initialize the IO map */
122326947304SEvan Yan 	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO,
122426947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
122526947304SEvan Yan 		DEBUG0("Can not initalize ntbridge memory resource map\n");
122626947304SEvan Yan 		return (PCICFG_FAILURE);
122726947304SEvan Yan 	}
122826947304SEvan Yan 
122926947304SEvan Yan 	return (PCICFG_SUCCESS);
123026947304SEvan Yan }
123126947304SEvan Yan 
123226947304SEvan Yan static int
123326947304SEvan Yan pcicfg_ntbridge_configure_done(dev_info_t *dip)
123426947304SEvan Yan {
123526947304SEvan Yan 	pcicfg_range_t range[PCICFG_RANGE_LEN];
123626947304SEvan Yan 	pcicfg_phdl_t		*entry;
123726947304SEvan Yan 	uint_t			len;
123826947304SEvan Yan 	pcicfg_bus_range_t	bus_range;
123926947304SEvan Yan 	int			new_bus_range[2];
124026947304SEvan Yan 
124126947304SEvan Yan 	DEBUG1("Configuring children for %llx\n", dip);
124226947304SEvan Yan 
124326947304SEvan Yan 	entry = pcicfg_find_phdl(dip);
124426947304SEvan Yan 	ASSERT(entry);
124526947304SEvan Yan 
124626947304SEvan Yan 	bzero((caddr_t)range,
124726947304SEvan Yan 	    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
124826947304SEvan Yan 	range[1].child_hi = range[1].parent_hi |=
124926947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
125026947304SEvan Yan 	range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base;
125126947304SEvan Yan 
125226947304SEvan Yan 	range[0].child_hi = range[0].parent_hi |=
125326947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_IO);
125426947304SEvan Yan 	range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base;
125526947304SEvan Yan 
125626947304SEvan Yan 	len = sizeof (pcicfg_bus_range_t);
125726947304SEvan Yan 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
125826947304SEvan Yan 	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
125926947304SEvan Yan 		DEBUG0("no bus-range property\n");
126026947304SEvan Yan 		return (PCICFG_FAILURE);
126126947304SEvan Yan 	}
126226947304SEvan Yan 
126326947304SEvan Yan 	new_bus_range[0] = bus_range.lo;	/* primary bus number */
126426947304SEvan Yan 	if (entry->highest_bus) {	/* secondary bus number */
126526947304SEvan Yan 		if (entry->highest_bus < bus_range.lo) {
126626947304SEvan Yan 			cmn_err(CE_WARN,
126726947304SEvan Yan 			    "ntbridge bus range invalid !(%d,%d)\n",
126826947304SEvan Yan 			    bus_range.lo, entry->highest_bus);
126926947304SEvan Yan 			new_bus_range[1] = bus_range.lo + entry->highest_bus;
127026947304SEvan Yan 		}
127126947304SEvan Yan 		else
127226947304SEvan Yan 			new_bus_range[1] = entry->highest_bus;
127326947304SEvan Yan 	}
127426947304SEvan Yan 	else
127526947304SEvan Yan 		new_bus_range[1] = bus_range.hi;
127626947304SEvan Yan 
127726947304SEvan Yan 	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n",
127826947304SEvan Yan 	    new_bus_range[0], new_bus_range[1]);
127926947304SEvan Yan 
128026947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
128126947304SEvan Yan 	    "bus-range", new_bus_range, 2) != DDI_SUCCESS) {
128226947304SEvan Yan 		DEBUG0("Failed to set bus-range property");
128326947304SEvan Yan 		entry->error = PCICFG_FAILURE;
128426947304SEvan Yan 		return (PCICFG_FAILURE);
128526947304SEvan Yan 	}
128626947304SEvan Yan 
128726947304SEvan Yan #ifdef DEBUG
128826947304SEvan Yan 	{
128926947304SEvan Yan 		uint64_t	unused;
129026947304SEvan Yan 		unused = pcicfg_unused_space(&entry->io_hole, &len);
129126947304SEvan Yan 		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
129226947304SEvan Yan 		    unused, len);
129326947304SEvan Yan 	}
129426947304SEvan Yan #endif
129526947304SEvan Yan 
129626947304SEvan Yan 	range[0].size_lo = entry->io_len;
129726947304SEvan Yan 	if (pcicfg_update_ranges_prop(dip, &range[0])) {
129826947304SEvan Yan 		DEBUG0("Failed to update ranges (i/o)\n");
129926947304SEvan Yan 		entry->error = PCICFG_FAILURE;
130026947304SEvan Yan 		return (PCICFG_FAILURE);
130126947304SEvan Yan 	}
130226947304SEvan Yan 
130326947304SEvan Yan #ifdef DEBUG
130426947304SEvan Yan 	{
130526947304SEvan Yan 		uint64_t	unused;
130626947304SEvan Yan 		unused = pcicfg_unused_space(&entry->mem_hole, &len);
130726947304SEvan Yan 		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
130826947304SEvan Yan 		    unused, len);
130926947304SEvan Yan 	}
131026947304SEvan Yan #endif
131126947304SEvan Yan 
131226947304SEvan Yan 	range[1].size_lo = entry->memory_len;
131326947304SEvan Yan 	if (pcicfg_update_ranges_prop(dip, &range[1])) {
131426947304SEvan Yan 		DEBUG0("Failed to update ranges (memory)\n");
131526947304SEvan Yan 		entry->error = PCICFG_FAILURE;
131626947304SEvan Yan 		return (PCICFG_FAILURE);
131726947304SEvan Yan 	}
131826947304SEvan Yan 
131926947304SEvan Yan 	return (PCICFG_SUCCESS);
132026947304SEvan Yan }
132126947304SEvan Yan 
132226947304SEvan Yan static int
132326947304SEvan Yan pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
132426947304SEvan Yan {
132526947304SEvan Yan 
132626947304SEvan Yan 	dev_info_t	*new_ntbridgechild;
132726947304SEvan Yan 	int 		len, bus;
132826947304SEvan Yan 	uint16_t	vid;
132926947304SEvan Yan 	ddi_acc_handle_t	config_handle;
133026947304SEvan Yan 	pcicfg_bus_range_t pci_bus_range;
133126947304SEvan Yan 
133226947304SEvan Yan 	len = sizeof (pcicfg_bus_range_t);
133326947304SEvan Yan 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
133426947304SEvan Yan 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
133526947304SEvan Yan 		DEBUG0("no bus-range property\n");
133626947304SEvan Yan 		return (PCICFG_FAILURE);
133726947304SEvan Yan 	}
133826947304SEvan Yan 
133926947304SEvan Yan 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
134026947304SEvan Yan 
134126947304SEvan Yan 	if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
134226947304SEvan Yan 	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) {
134326947304SEvan Yan 
134426947304SEvan Yan 		DEBUG0("pcicfg: Failed to alloc test node\n");
134526947304SEvan Yan 		return (PCICFG_FAILURE);
134626947304SEvan Yan 	}
134726947304SEvan Yan 
134826947304SEvan Yan 	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
134926947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
135026947304SEvan Yan 		cmn_err(CE_WARN,
135126947304SEvan Yan 		"Unconfigure: Failed to add conf reg prop for ntbridge "
135226947304SEvan Yan 		    "child.\n");
135326947304SEvan Yan 		(void) ndi_devi_free(new_ntbridgechild);
135426947304SEvan Yan 		return (PCICFG_FAILURE);
135526947304SEvan Yan 	}
135626947304SEvan Yan 
135726947304SEvan Yan 	if (pcicfg_config_setup(new_ntbridgechild, &config_handle)
135826947304SEvan Yan 	    != DDI_SUCCESS) {
135926947304SEvan Yan 		cmn_err(CE_WARN,
136026947304SEvan Yan 		    "pcicfg: Cannot map ntbridge child %x\n", devno);
136126947304SEvan Yan 		(void) ndi_devi_free(new_ntbridgechild);
136226947304SEvan Yan 		return (PCICFG_FAILURE);
136326947304SEvan Yan 	}
136426947304SEvan Yan 
136526947304SEvan Yan 	/*
136626947304SEvan Yan 	 * See if there is any PCI HW at this location
136726947304SEvan Yan 	 * by reading the Vendor ID.  If it returns with 0xffff
136826947304SEvan Yan 	 * then there is no hardware at this location.
136926947304SEvan Yan 	 */
137026947304SEvan Yan 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
137126947304SEvan Yan 
137226947304SEvan Yan 	pci_config_teardown(&config_handle);
137326947304SEvan Yan 	(void) ndi_devi_free(new_ntbridgechild);
137426947304SEvan Yan 	if (vid	== 0xffff)
137526947304SEvan Yan 		return (PCICFG_NODEVICE);
137626947304SEvan Yan 
137726947304SEvan Yan 	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
137826947304SEvan Yan }
137926947304SEvan Yan 
138026947304SEvan Yan static int
138126947304SEvan Yan pcicfg_ntbridge_unconfigure(dev_info_t *dip)
138226947304SEvan Yan {
138326947304SEvan Yan 	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
138426947304SEvan Yan 	uint_t			*bus;
138526947304SEvan Yan 	int			k, rc = PCICFG_FAILURE;
138626947304SEvan Yan 
138726947304SEvan Yan 	if (entry->memory_len)
138826947304SEvan Yan 		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
138926947304SEvan Yan 			DEBUG1("cannot destroy ntbridge memory map size=%x\n",
139026947304SEvan Yan 			    entry->memory_len);
139126947304SEvan Yan 			return (PCICFG_FAILURE);
139226947304SEvan Yan 		}
139326947304SEvan Yan 	if (entry->io_len)
139426947304SEvan Yan 		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
139526947304SEvan Yan 			DEBUG1("cannot destroy ntbridge io map size=%x\n",
139626947304SEvan Yan 			    entry->io_len);
139726947304SEvan Yan 			return (PCICFG_FAILURE);
139826947304SEvan Yan 		}
139926947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
140026947304SEvan Yan 	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
140126947304SEvan Yan 	    &k) != DDI_PROP_SUCCESS) {
140226947304SEvan Yan 		DEBUG0("ntbridge: Failed to read bus-range property\n");
140326947304SEvan Yan 		return (rc);
140426947304SEvan Yan 	}
140526947304SEvan Yan 
140626947304SEvan Yan 	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
140726947304SEvan Yan 	    bus[0], bus[1] - bus[0] + 1);
140826947304SEvan Yan 
140926947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip),
141026947304SEvan Yan 	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
141126947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
141226947304SEvan Yan 		DEBUG0("ntbridge: Failed to free a bus number\n");
141326947304SEvan Yan 		/*
141426947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
141526947304SEvan Yan 		 */
141626947304SEvan Yan 		kmem_free((caddr_t)bus, k);
141726947304SEvan Yan 
141826947304SEvan Yan 		return (rc);
141926947304SEvan Yan 	}
142026947304SEvan Yan 
142126947304SEvan Yan 	/*
142226947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
142326947304SEvan Yan 	 */
142426947304SEvan Yan 	kmem_free((caddr_t)bus, k);
142526947304SEvan Yan 
142626947304SEvan Yan 	/*
142726947304SEvan Yan 	 * Since our resources will be freed at the parent level,
142826947304SEvan Yan 	 * just reset these values.
142926947304SEvan Yan 	 */
143026947304SEvan Yan 	entry->memory_len = 0;
143126947304SEvan Yan 	entry->io_len = 0;
143226947304SEvan Yan 	/* the following will also free hole data. */
143326947304SEvan Yan 	return (pcicfg_destroy_phdl(dip));
143426947304SEvan Yan 
143526947304SEvan Yan }
143626947304SEvan Yan 
143726947304SEvan Yan static int
143826947304SEvan Yan pcicfg_is_ntbridge(dev_info_t *dip)
143926947304SEvan Yan {
144026947304SEvan Yan 	ddi_acc_handle_t	config_handle;
144126947304SEvan Yan 	uint8_t		class, subclass;
144226947304SEvan Yan 	int		rc = DDI_SUCCESS;
144326947304SEvan Yan 
144426947304SEvan Yan 	if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) {
144526947304SEvan Yan 		cmn_err(CE_WARN,
144626947304SEvan Yan 		    "pcicfg: cannot map config space, to get map type\n");
144726947304SEvan Yan 		return (DDI_FAILURE);
144826947304SEvan Yan 	}
144926947304SEvan Yan 	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
145026947304SEvan Yan 	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
145126947304SEvan Yan 
145226947304SEvan Yan 	/* check for class=6, subclass=9, for non transparent bridges.  */
145326947304SEvan Yan 	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
145426947304SEvan Yan 		rc = DDI_FAILURE;
145526947304SEvan Yan 
145626947304SEvan Yan 	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
145726947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID),
145826947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID),
145926947304SEvan Yan 	    rc);
146026947304SEvan Yan 	pci_config_teardown(&config_handle);
146126947304SEvan Yan 	return (rc);
146226947304SEvan Yan }
146326947304SEvan Yan 
146426947304SEvan Yan /*
146526947304SEvan Yan  * this function is called only for SPARC platforms, where we may have
146626947304SEvan Yan  * a mix n' match of direct vs indirectly mapped configuration space.
146726947304SEvan Yan  * On x86, this function does not get called. We always return TRUE
146826947304SEvan Yan  * via a macro for x86.
146926947304SEvan Yan  */
147026947304SEvan Yan /*ARGSUSED*/
147126947304SEvan Yan static int
147226947304SEvan Yan pcicfg_indirect_map(dev_info_t *dip)
147326947304SEvan Yan {
147426947304SEvan Yan #if defined(__sparc)
147526947304SEvan Yan 	int rc = DDI_FAILURE;
147626947304SEvan Yan 
147726947304SEvan Yan 	if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
147826947304SEvan Yan 	    PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
147926947304SEvan Yan 		rc = DDI_SUCCESS;
148026947304SEvan Yan 	else
148126947304SEvan Yan 		if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
148226947304SEvan Yan 		    0, PCI_BUS_CONF_MAP_PROP,
148326947304SEvan Yan 		    DDI_FAILURE) != DDI_FAILURE)
148426947304SEvan Yan 			rc = DDI_SUCCESS;
148526947304SEvan Yan 	DEBUG1("pci conf map = %d", rc);
148626947304SEvan Yan 	return (rc);
148726947304SEvan Yan #else
148826947304SEvan Yan 	return (DDI_SUCCESS);
148926947304SEvan Yan #endif
149026947304SEvan Yan }
149126947304SEvan Yan 
149226947304SEvan Yan static uint_t
149326947304SEvan Yan pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
149426947304SEvan Yan 				uint64_t *boundlen, uint_t space_type)
149526947304SEvan Yan {
149626947304SEvan Yan 	int		length, found = DDI_FAILURE, acount, i, ibridge;
149726947304SEvan Yan 	pci_regspec_t	*assigned;
149826947304SEvan Yan 
149926947304SEvan Yan 	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
150026947304SEvan Yan 		return (found);
150126947304SEvan Yan 
150226947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
150326947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
150426947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
150526947304SEvan Yan 		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
150626947304SEvan Yan 		return (found);
150726947304SEvan Yan 	}
150826947304SEvan Yan 	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
150926947304SEvan Yan 	    ddi_driver_name(dip));
151026947304SEvan Yan 
151126947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
151226947304SEvan Yan 
151326947304SEvan Yan 	for (i = 0; i < acount; i++) {
151426947304SEvan Yan 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
151526947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
151626947304SEvan Yan 		    (space_type == PCI_BASE_SPACE_MEM)) {
151726947304SEvan Yan 			found = DDI_SUCCESS;
151826947304SEvan Yan 			break;
151926947304SEvan Yan 		} else {
152026947304SEvan Yan 			if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
152126947304SEvan Yan 			    pcicfg_indirect_map_devs[ibridge].\
152226947304SEvan Yan 			    io_range_bar_offset) &&
152326947304SEvan Yan 			    (space_type == PCI_BASE_SPACE_IO)) {
152426947304SEvan Yan 				found = DDI_SUCCESS;
152526947304SEvan Yan 				break;
152626947304SEvan Yan 			}
152726947304SEvan Yan 		}
152826947304SEvan Yan 	}
152926947304SEvan Yan 	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
153026947304SEvan Yan 	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
153126947304SEvan Yan 
153226947304SEvan Yan 	if (found == DDI_SUCCESS)  {
153326947304SEvan Yan 		*boundbase = assigned[i].pci_phys_low;
153426947304SEvan Yan 		*boundlen = assigned[i].pci_size_low;
153526947304SEvan Yan 	}
153626947304SEvan Yan 
153726947304SEvan Yan 	kmem_free(assigned, length);
153826947304SEvan Yan 	return (found);
153926947304SEvan Yan }
154026947304SEvan Yan 
154126947304SEvan Yan /*
154226947304SEvan Yan  * This will turn  resources allocated by pcicfg_configure()
154326947304SEvan Yan  * and remove the device tree from the Hotplug Connection (CN)
154426947304SEvan Yan  * and below.  The routine assumes the devices have their
154526947304SEvan Yan  * drivers detached.
154626947304SEvan Yan  */
154726947304SEvan Yan int
154826947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
154926947304SEvan Yan     pcicfg_flags_t flags)
155026947304SEvan Yan {
155126947304SEvan Yan 	dev_info_t *child_dip;
155226947304SEvan Yan 	int func;
155326947304SEvan Yan 	int i;
155426947304SEvan Yan 	int max_function;
155526947304SEvan Yan 	int trans_device;
1556c0da6274SZhi-Jun Robin Fu 	int circ;
1557c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
155826947304SEvan Yan 
155926947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
156026947304SEvan Yan 		max_function = PCICFG_MAX_ARI_FUNCTION;
156126947304SEvan Yan 	else
156226947304SEvan Yan 		max_function = PCICFG_MAX_FUNCTION;
156326947304SEvan Yan 
156426947304SEvan Yan 	/*
156526947304SEvan Yan 	 * Cycle through devices to make sure none are busy.
156626947304SEvan Yan 	 * If a single device is busy fail the whole unconfigure.
156726947304SEvan Yan 	 */
1568c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
1569c0da6274SZhi-Jun Robin Fu 
1570c0da6274SZhi-Jun Robin Fu 	ndi_devi_enter(devi, &circ);
157126947304SEvan Yan 	for (func = 0; func < max_function; func++) {
157226947304SEvan Yan 
157326947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
157426947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
157526947304SEvan Yan 		else
157626947304SEvan Yan 			trans_device = device;
157726947304SEvan Yan 
157826947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device,
157926947304SEvan Yan 		    (func & 0x7))) == NULL)
158026947304SEvan Yan 			continue;
158126947304SEvan Yan 
158226947304SEvan Yan 		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
158326947304SEvan Yan 			continue;
158426947304SEvan Yan 		/*
158526947304SEvan Yan 		 * Device function is busy. Before returning we have to
158626947304SEvan Yan 		 * put all functions back online which were taken
158726947304SEvan Yan 		 * offline during the process.
158826947304SEvan Yan 		 */
158926947304SEvan Yan 		DEBUG2("Device [0x%x] function [%x] is busy\n", device, func);
159026947304SEvan Yan 		/*
159126947304SEvan Yan 		 * If we are only asked to offline one specific function,
159226947304SEvan Yan 		 * and that fails, we just simply return.
159326947304SEvan Yan 		 */
159426947304SEvan Yan 		if (function != PCICFG_ALL_FUNC)
159526947304SEvan Yan 			return (PCICFG_FAILURE);
159626947304SEvan Yan 
159726947304SEvan Yan 		for (i = 0; i < func; i++) {
159826947304SEvan Yan 
159926947304SEvan Yan 			if (max_function == PCICFG_MAX_ARI_FUNCTION)
160026947304SEvan Yan 				trans_device = i >> 3;
160126947304SEvan Yan 
160226947304SEvan Yan 			if ((child_dip =
160326947304SEvan Yan 			    pcicfg_devi_find(devi, trans_device, (i & 7)))
160426947304SEvan Yan 			    == NULL) {
160526947304SEvan Yan 				DEBUG0(
160626947304SEvan Yan 				    "No more devices to put back on line!!\n");
160726947304SEvan Yan 				/*
160826947304SEvan Yan 				 * Made it through all functions
160926947304SEvan Yan 				 */
161026947304SEvan Yan 				continue;
161126947304SEvan Yan 			}
161226947304SEvan Yan 			if (ndi_devi_online(child_dip, NDI_CONFIG)
161326947304SEvan Yan 			    != NDI_SUCCESS) {
161426947304SEvan Yan 				DEBUG0("Failed to put back devices state\n");
1615c0da6274SZhi-Jun Robin Fu 				goto fail;
161626947304SEvan Yan 			}
161726947304SEvan Yan 		}
1618c0da6274SZhi-Jun Robin Fu 		goto fail;
161926947304SEvan Yan 	}
162026947304SEvan Yan 
162126947304SEvan Yan 	/*
162226947304SEvan Yan 	 * Now, tear down all devinfo nodes for this Connector.
162326947304SEvan Yan 	 */
162426947304SEvan Yan 	for (func = 0; func < max_function; func++) {
162526947304SEvan Yan 
162626947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
162726947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
162826947304SEvan Yan 		else
162926947304SEvan Yan 			trans_device = device;
163026947304SEvan Yan 
163126947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi,
163226947304SEvan Yan 		    trans_device, (func & 7))) == NULL) {
163326947304SEvan Yan 			DEBUG0("No more devices to tear down!\n");
163426947304SEvan Yan 			continue;
163526947304SEvan Yan 		}
163626947304SEvan Yan 
163726947304SEvan Yan 		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
163826947304SEvan Yan 		    trans_device, (func & 7));
163926947304SEvan Yan 
164026947304SEvan Yan 		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
164126947304SEvan Yan 			if (pcicfg_ntbridge_unconfigure(child_dip) !=
164226947304SEvan Yan 			    PCICFG_SUCCESS) {
164326947304SEvan Yan 				cmn_err(CE_WARN,
164426947304SEvan Yan 				    "ntbridge: unconfigure failed\n");
1645c0da6274SZhi-Jun Robin Fu 				goto fail;
164626947304SEvan Yan 			}
164726947304SEvan Yan 
1648c0da6274SZhi-Jun Robin Fu 		if (pcicfg_teardown_device(child_dip, flags, is_pcie)
164926947304SEvan Yan 		    != PCICFG_SUCCESS) {
165026947304SEvan Yan 			DEBUG2("Failed to tear down device [0x%x]"
165126947304SEvan Yan 			    "function [0x%x]\n",
165226947304SEvan Yan 			    trans_device, func & 7);
1653c0da6274SZhi-Jun Robin Fu 			goto fail;
165426947304SEvan Yan 		}
165526947304SEvan Yan 	}
165626947304SEvan Yan 
165726947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
165826947304SEvan Yan 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
165926947304SEvan Yan 		(void) pcie_ari_disable(devi);
166026947304SEvan Yan 	}
166126947304SEvan Yan 
1662c0da6274SZhi-Jun Robin Fu 	ndi_devi_exit(devi, circ);
166326947304SEvan Yan 	return (PCICFG_SUCCESS);
1664c0da6274SZhi-Jun Robin Fu 
1665c0da6274SZhi-Jun Robin Fu fail:
1666c0da6274SZhi-Jun Robin Fu 	ndi_devi_exit(devi, circ);
1667c0da6274SZhi-Jun Robin Fu 	return (PCICFG_FAILURE);
166826947304SEvan Yan }
166926947304SEvan Yan 
167026947304SEvan Yan static int
1671c0da6274SZhi-Jun Robin Fu pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
167226947304SEvan Yan {
167326947304SEvan Yan 	ddi_acc_handle_t	config_handle;
167426947304SEvan Yan 
167526947304SEvan Yan 	/*
167626947304SEvan Yan 	 * Free up resources associated with 'dip'
167726947304SEvan Yan 	 */
167826947304SEvan Yan 	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
167926947304SEvan Yan 		DEBUG0("Failed to free resources\n");
168026947304SEvan Yan 		return (PCICFG_FAILURE);
168126947304SEvan Yan 	}
168226947304SEvan Yan 
168326947304SEvan Yan 	/*
168426947304SEvan Yan 	 * This will disable the device
168526947304SEvan Yan 	 */
168626947304SEvan Yan 	if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) {
168726947304SEvan Yan 		return (PCICFG_FAILURE);
168826947304SEvan Yan 	}
168926947304SEvan Yan 
169026947304SEvan Yan 	pcicfg_device_off(config_handle);
169126947304SEvan Yan 	pci_config_teardown(&config_handle);
169226947304SEvan Yan 
169326947304SEvan Yan 	/*
1694c0da6274SZhi-Jun Robin Fu 	 * free pcie_bus_t for the sub-tree
1695c0da6274SZhi-Jun Robin Fu 	 */
1696c0da6274SZhi-Jun Robin Fu 	if (is_pcie) {
1697c0da6274SZhi-Jun Robin Fu 		if (ddi_get_child(dip) != NULL)
1698c0da6274SZhi-Jun Robin Fu 			pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
1699c0da6274SZhi-Jun Robin Fu 
1700c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(dip, PCIE_BUS_ALL);
1701c0da6274SZhi-Jun Robin Fu 	}
1702c0da6274SZhi-Jun Robin Fu 
1703c0da6274SZhi-Jun Robin Fu 	/*
170426947304SEvan Yan 	 * The framework provides this routine which can
170526947304SEvan Yan 	 * tear down a sub-tree.
170626947304SEvan Yan 	 */
170726947304SEvan Yan 	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
170826947304SEvan Yan 		DEBUG0("Failed to offline and remove node\n");
170926947304SEvan Yan 		return (PCICFG_FAILURE);
171026947304SEvan Yan 	}
171126947304SEvan Yan 
171226947304SEvan Yan 	return (PCICFG_SUCCESS);
171326947304SEvan Yan }
171426947304SEvan Yan 
171526947304SEvan Yan /*
171626947304SEvan Yan  * BEGIN GENERIC SUPPORT ROUTINES
171726947304SEvan Yan  */
171826947304SEvan Yan static pcicfg_phdl_t *
171926947304SEvan Yan pcicfg_find_phdl(dev_info_t *dip)
172026947304SEvan Yan {
172126947304SEvan Yan 	pcicfg_phdl_t *entry;
172226947304SEvan Yan 	mutex_enter(&pcicfg_list_mutex);
172326947304SEvan Yan 	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
172426947304SEvan Yan 		if (entry->dip == dip) {
172526947304SEvan Yan 			mutex_exit(&pcicfg_list_mutex);
172626947304SEvan Yan 			return (entry);
172726947304SEvan Yan 		}
172826947304SEvan Yan 	}
172926947304SEvan Yan 	mutex_exit(&pcicfg_list_mutex);
173026947304SEvan Yan 
173126947304SEvan Yan 	/*
173226947304SEvan Yan 	 * Did'nt find entry - create one
173326947304SEvan Yan 	 */
173426947304SEvan Yan 	return (pcicfg_create_phdl(dip));
173526947304SEvan Yan }
173626947304SEvan Yan 
173726947304SEvan Yan static pcicfg_phdl_t *
173826947304SEvan Yan pcicfg_create_phdl(dev_info_t *dip)
173926947304SEvan Yan {
174026947304SEvan Yan 	pcicfg_phdl_t *new;
174126947304SEvan Yan 
174226947304SEvan Yan 	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t),
174326947304SEvan Yan 	    KM_SLEEP);
174426947304SEvan Yan 
174526947304SEvan Yan 	new->dip = dip;
174626947304SEvan Yan 	mutex_enter(&pcicfg_list_mutex);
174726947304SEvan Yan 	new->next = pcicfg_phdl_list;
174826947304SEvan Yan 	pcicfg_phdl_list = new;
174926947304SEvan Yan 	mutex_exit(&pcicfg_list_mutex);
175026947304SEvan Yan 
175126947304SEvan Yan 	return (new);
175226947304SEvan Yan }
175326947304SEvan Yan 
175426947304SEvan Yan static int
175526947304SEvan Yan pcicfg_destroy_phdl(dev_info_t *dip)
175626947304SEvan Yan {
175726947304SEvan Yan 	pcicfg_phdl_t *entry;
175826947304SEvan Yan 	pcicfg_phdl_t *follow = NULL;
175926947304SEvan Yan 
176026947304SEvan Yan 	mutex_enter(&pcicfg_list_mutex);
176126947304SEvan Yan 	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
176226947304SEvan Yan 	    entry = entry->next) {
176326947304SEvan Yan 		if (entry->dip == dip) {
176426947304SEvan Yan 			if (entry == pcicfg_phdl_list) {
176526947304SEvan Yan 				pcicfg_phdl_list = entry->next;
176626947304SEvan Yan 			} else {
176726947304SEvan Yan 				follow->next = entry->next;
176826947304SEvan Yan 			}
176926947304SEvan Yan 			/*
177026947304SEvan Yan 			 * If this entry has any allocated memory
177126947304SEvan Yan 			 * or IO space associated with it, that
177226947304SEvan Yan 			 * must be freed up.
177326947304SEvan Yan 			 */
177426947304SEvan Yan 			if (entry->memory_len > 0) {
177526947304SEvan Yan 				(void) ndi_ra_free(ddi_get_parent(dip),
177626947304SEvan Yan 				    entry->memory_base,
177726947304SEvan Yan 				    entry->memory_len,
177826947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
177926947304SEvan Yan 			}
178026947304SEvan Yan 			pcicfg_free_hole(&entry->mem_hole);
178126947304SEvan Yan 
178226947304SEvan Yan 			if (entry->io_len > 0) {
178326947304SEvan Yan 				(void) ndi_ra_free(ddi_get_parent(dip),
178426947304SEvan Yan 				    entry->io_base,
178526947304SEvan Yan 				    entry->io_len,
178626947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS);
178726947304SEvan Yan 			}
178826947304SEvan Yan 			pcicfg_free_hole(&entry->io_hole);
178926947304SEvan Yan 
179026947304SEvan Yan 			/*
179126947304SEvan Yan 			 * Destroy this entry
179226947304SEvan Yan 			 */
179326947304SEvan Yan 			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
179426947304SEvan Yan 			mutex_exit(&pcicfg_list_mutex);
179526947304SEvan Yan 			return (PCICFG_SUCCESS);
179626947304SEvan Yan 		}
179726947304SEvan Yan 	}
179826947304SEvan Yan 	mutex_exit(&pcicfg_list_mutex);
179926947304SEvan Yan 	/*
180026947304SEvan Yan 	 * Did'nt find the entry
180126947304SEvan Yan 	 */
180226947304SEvan Yan 	return (PCICFG_FAILURE);
180326947304SEvan Yan }
180426947304SEvan Yan 
180526947304SEvan Yan static int
180626947304SEvan Yan pcicfg_program_ap(dev_info_t *dip)
180726947304SEvan Yan {
180826947304SEvan Yan 	pcicfg_phdl_t *phdl;
180926947304SEvan Yan 	uint8_t header_type;
181026947304SEvan Yan 	ddi_acc_handle_t handle;
181126947304SEvan Yan 	pcicfg_phdl_t *entry;
181226947304SEvan Yan 
181326947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
181426947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
181526947304SEvan Yan 		return (PCICFG_FAILURE);
181626947304SEvan Yan 
181726947304SEvan Yan 	}
181826947304SEvan Yan 
181926947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
182026947304SEvan Yan 
182126947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
182226947304SEvan Yan 
182326947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
182426947304SEvan Yan 
182526947304SEvan Yan 		if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) {
182626947304SEvan Yan 			DEBUG0("Not enough memory to hotplug\n");
182726947304SEvan Yan 			(void) pcicfg_destroy_phdl(dip);
182826947304SEvan Yan 			return (PCICFG_FAILURE);
182926947304SEvan Yan 		}
183026947304SEvan Yan 
183126947304SEvan Yan 		phdl = pcicfg_find_phdl(dip);
183226947304SEvan Yan 		ASSERT(phdl);
183326947304SEvan Yan 
183426947304SEvan Yan 		(void) pcicfg_bridge_assign(dip, (void *)phdl);
183526947304SEvan Yan 
183626947304SEvan Yan 		if (phdl->error != PCICFG_SUCCESS) {
183726947304SEvan Yan 			DEBUG0("Problem assigning bridge\n");
183826947304SEvan Yan 			(void) pcicfg_destroy_phdl(dip);
183926947304SEvan Yan 			return (phdl->error);
184026947304SEvan Yan 		}
184126947304SEvan Yan 
184226947304SEvan Yan 		/*
184326947304SEvan Yan 		 * Successfully allocated and assigned
184426947304SEvan Yan 		 * memory.  Set the memory and IO length
184526947304SEvan Yan 		 * to zero so when the handle is freed up
184626947304SEvan Yan 		 * it will not de-allocate assigned resources.
184726947304SEvan Yan 		 */
184826947304SEvan Yan 		entry = (pcicfg_phdl_t *)phdl;
184926947304SEvan Yan 
185026947304SEvan Yan 		entry->memory_len = entry->io_len = 0;
185126947304SEvan Yan 
185226947304SEvan Yan 		/*
185326947304SEvan Yan 		 * Free up the "entry" structure.
185426947304SEvan Yan 		 */
185526947304SEvan Yan 		(void) pcicfg_destroy_phdl(dip);
185626947304SEvan Yan 	} else {
185726947304SEvan Yan 		if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) {
185826947304SEvan Yan 			return (PCICFG_FAILURE);
185926947304SEvan Yan 		}
186026947304SEvan Yan 	}
186126947304SEvan Yan 	return (PCICFG_SUCCESS);
186226947304SEvan Yan }
186326947304SEvan Yan 
186426947304SEvan Yan static int
186526947304SEvan Yan pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
186626947304SEvan Yan {
186726947304SEvan Yan 	ddi_acc_handle_t handle;
186826947304SEvan Yan 	pci_regspec_t *reg;
186926947304SEvan Yan 	int length;
187026947304SEvan Yan 	int rcount;
187126947304SEvan Yan 	int i;
187226947304SEvan Yan 	int offset;
187326947304SEvan Yan 	uint64_t mem_answer;
187426947304SEvan Yan 	uint32_t io_answer;
187526947304SEvan Yan 	int count;
187626947304SEvan Yan 	uint8_t header_type;
187726947304SEvan Yan 	pcicfg_range_t range[PCICFG_RANGE_LEN];
187826947304SEvan Yan 	int bus_range[2];
187926947304SEvan Yan 
188026947304SEvan Yan 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
188126947304SEvan Yan 
188226947304SEvan Yan 	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
188326947304SEvan Yan 
188426947304SEvan Yan 	if (entry == NULL) {
188526947304SEvan Yan 		DEBUG0("Failed to get entry\n");
188626947304SEvan Yan 		return (DDI_WALK_TERMINATE);
188726947304SEvan Yan 	}
188826947304SEvan Yan 
188926947304SEvan Yan 	entry->error = PCICFG_SUCCESS;
189026947304SEvan Yan 
189126947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
189226947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
189326947304SEvan Yan 		entry->error = PCICFG_FAILURE;
189426947304SEvan Yan 		return (DDI_WALK_TERMINATE);
189526947304SEvan Yan 	}
189626947304SEvan Yan 
189726947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
189826947304SEvan Yan 
189926947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
190026947304SEvan Yan 
190126947304SEvan Yan 		bzero((caddr_t)range,
190226947304SEvan Yan 		    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
190326947304SEvan Yan 
190426947304SEvan Yan 		(void) pcicfg_setup_bridge(entry, handle, dip);
190526947304SEvan Yan 
190626947304SEvan Yan 		range[0].child_hi = range[0].parent_hi |=
190726947304SEvan Yan 		    (PCI_REG_REL_M | PCI_ADDR_IO);
190826947304SEvan Yan 		range[0].child_lo = range[0].parent_lo =
190926947304SEvan Yan 		    entry->io_last;
191026947304SEvan Yan 		range[1].child_hi = range[1].parent_hi |=
191126947304SEvan Yan 		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
191226947304SEvan Yan 		range[1].child_lo = range[1].parent_lo =
191326947304SEvan Yan 		    entry->memory_last;
191426947304SEvan Yan 
191526947304SEvan Yan 		ndi_devi_enter(dip, &count);
191626947304SEvan Yan 		ddi_walk_devs(ddi_get_child(dip),
191726947304SEvan Yan 		    pcicfg_bridge_assign, (void *)entry);
191826947304SEvan Yan 		ndi_devi_exit(dip, count);
191926947304SEvan Yan 
192026947304SEvan Yan 		(void) pcicfg_update_bridge(entry, handle);
192126947304SEvan Yan 
192226947304SEvan Yan 		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
192326947304SEvan Yan 		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
192426947304SEvan Yan 
192526947304SEvan Yan 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
192626947304SEvan Yan 		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
192726947304SEvan Yan 			DEBUG0("Failed to set bus-range property");
192826947304SEvan Yan 			entry->error = PCICFG_FAILURE;
192926947304SEvan Yan 			return (DDI_WALK_TERMINATE);
193026947304SEvan Yan 		}
193126947304SEvan Yan 
193226947304SEvan Yan 		if (entry->io_len > 0) {
193326947304SEvan Yan 			range[0].size_lo = entry->io_last - entry->io_base;
193426947304SEvan Yan 			if (pcicfg_update_ranges_prop(dip, &range[0])) {
193526947304SEvan Yan 				DEBUG0("Failed to update ranges (i/o)\n");
193626947304SEvan Yan 				entry->error = PCICFG_FAILURE;
193726947304SEvan Yan 				return (DDI_WALK_TERMINATE);
193826947304SEvan Yan 			}
193926947304SEvan Yan 		}
194026947304SEvan Yan 		if (entry->memory_len > 0) {
194126947304SEvan Yan 			range[1].size_lo =
194226947304SEvan Yan 			    entry->memory_last - entry->memory_base;
194326947304SEvan Yan 			if (pcicfg_update_ranges_prop(dip, &range[1])) {
194426947304SEvan Yan 				DEBUG0("Failed to update ranges (memory)\n");
194526947304SEvan Yan 				entry->error = PCICFG_FAILURE;
194626947304SEvan Yan 				return (DDI_WALK_TERMINATE);
194726947304SEvan Yan 			}
194826947304SEvan Yan 		}
194926947304SEvan Yan 
195026947304SEvan Yan 		(void) pcicfg_device_on(handle);
195126947304SEvan Yan 
195226947304SEvan Yan 		PCICFG_DUMP_BRIDGE_CONFIG(handle);
195326947304SEvan Yan 
195426947304SEvan Yan 		return (DDI_WALK_PRUNECHILD);
195526947304SEvan Yan 	}
195626947304SEvan Yan 
195726947304SEvan Yan 	/*
195826947304SEvan Yan 	 * If there is an interrupt pin set program
195926947304SEvan Yan 	 * interrupt line with default values.
196026947304SEvan Yan 	 */
196126947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
196226947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
196326947304SEvan Yan 	}
196426947304SEvan Yan 
196526947304SEvan Yan 	/*
196626947304SEvan Yan 	 * A single device (under a bridge).
196726947304SEvan Yan 	 * For each "reg" property with a length, allocate memory
196826947304SEvan Yan 	 * and program the base registers.
196926947304SEvan Yan 	 */
197026947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
197126947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
197226947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
197326947304SEvan Yan 		DEBUG0("Failed to read reg property\n");
197426947304SEvan Yan 		entry->error = PCICFG_FAILURE;
197526947304SEvan Yan 		return (DDI_WALK_TERMINATE);
197626947304SEvan Yan 	}
197726947304SEvan Yan 
197826947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
197926947304SEvan Yan 	offset = PCI_CONF_BASE0;
198026947304SEvan Yan 	for (i = 0; i < rcount; i++) {
198126947304SEvan Yan 		if ((reg[i].pci_size_low != 0)||
198226947304SEvan Yan 		    (reg[i].pci_size_hi != 0)) {
198326947304SEvan Yan 
198426947304SEvan Yan 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
198526947304SEvan Yan 
198626947304SEvan Yan 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
198726947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
198826947304SEvan Yan 
198926947304SEvan Yan 				(void) pcicfg_get_mem(entry,
199026947304SEvan Yan 				    reg[i].pci_size_low, &mem_answer);
199126947304SEvan Yan 				pci_config_put64(handle, offset, mem_answer);
199226947304SEvan Yan 				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
199326947304SEvan Yan 				    offset,
199426947304SEvan Yan 				    pci_config_get32(handle, offset));
199526947304SEvan Yan 				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
199626947304SEvan Yan 				    offset + 4,
199726947304SEvan Yan 				    pci_config_get32(handle, offset + 4));
199826947304SEvan Yan 
199926947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer);
200026947304SEvan Yan 				reg[i].pci_phys_mid  =
200126947304SEvan Yan 				    PCICFG_LOADDR(mem_answer);
200226947304SEvan Yan 
200326947304SEvan Yan 				break;
200426947304SEvan Yan 
200526947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
200626947304SEvan Yan 				/* allocate memory space from the allocator */
200726947304SEvan Yan 
200826947304SEvan Yan 				(void) pcicfg_get_mem(entry,
200926947304SEvan Yan 				    reg[i].pci_size_low, &mem_answer);
201026947304SEvan Yan 				pci_config_put32(handle,
201126947304SEvan Yan 				    offset, (uint32_t)mem_answer);
201226947304SEvan Yan 
201326947304SEvan Yan 				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
201426947304SEvan Yan 				    offset,
201526947304SEvan Yan 				    pci_config_get32(handle, offset));
201626947304SEvan Yan 
201726947304SEvan Yan 				reg[i].pci_phys_low = (uint32_t)mem_answer;
201826947304SEvan Yan 
201926947304SEvan Yan 				break;
202026947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
202126947304SEvan Yan 				/* allocate I/O space from the allocator */
202226947304SEvan Yan 
202326947304SEvan Yan 				(void) pcicfg_get_io(entry,
202426947304SEvan Yan 				    reg[i].pci_size_low, &io_answer);
202526947304SEvan Yan 				pci_config_put32(handle, offset, io_answer);
202626947304SEvan Yan 
202726947304SEvan Yan 				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
202826947304SEvan Yan 				    offset,
202926947304SEvan Yan 				    pci_config_get32(handle, offset));
203026947304SEvan Yan 
203126947304SEvan Yan 				reg[i].pci_phys_low = io_answer;
203226947304SEvan Yan 
203326947304SEvan Yan 				break;
203426947304SEvan Yan 			default:
203526947304SEvan Yan 				DEBUG0("Unknown register type\n");
203626947304SEvan Yan 				kmem_free(reg, length);
203726947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
203826947304SEvan Yan 				entry->error = PCICFG_FAILURE;
203926947304SEvan Yan 				return (DDI_WALK_TERMINATE);
204026947304SEvan Yan 			} /* switch */
204126947304SEvan Yan 
204226947304SEvan Yan 			/*
204326947304SEvan Yan 			 * Now that memory locations are assigned,
204426947304SEvan Yan 			 * update the assigned address property.
204526947304SEvan Yan 			 */
204626947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip,
204726947304SEvan Yan 			    &reg[i]) != PCICFG_SUCCESS) {
204826947304SEvan Yan 				kmem_free(reg, length);
204926947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
205026947304SEvan Yan 				entry->error = PCICFG_FAILURE;
205126947304SEvan Yan 				return (DDI_WALK_TERMINATE);
205226947304SEvan Yan 			}
205326947304SEvan Yan 		}
205426947304SEvan Yan 	}
205526947304SEvan Yan 	(void) pcicfg_device_on(handle);
205626947304SEvan Yan 
205726947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
205826947304SEvan Yan 
205926947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
206026947304SEvan Yan 	/*
206126947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
206226947304SEvan Yan 	 */
206326947304SEvan Yan 	kmem_free((caddr_t)reg, length);
206426947304SEvan Yan 
206526947304SEvan Yan 	return (DDI_WALK_CONTINUE);
206626947304SEvan Yan }
206726947304SEvan Yan 
206826947304SEvan Yan static int
206926947304SEvan Yan pcicfg_device_assign(dev_info_t *dip)
207026947304SEvan Yan {
207126947304SEvan Yan 	ddi_acc_handle_t	handle;
207226947304SEvan Yan 	pci_regspec_t		*reg;
207326947304SEvan Yan 	int			length;
207426947304SEvan Yan 	int			rcount;
207526947304SEvan Yan 	int			i;
207626947304SEvan Yan 	int			offset;
207726947304SEvan Yan 	ndi_ra_request_t	request;
207826947304SEvan Yan 	uint64_t		answer;
207926947304SEvan Yan 	uint64_t		alen;
208026947304SEvan Yan 
208126947304SEvan Yan 	DEBUG1("%llx now under configuration\n", dip);
208226947304SEvan Yan 
208326947304SEvan Yan 	/*
208426947304SEvan Yan 	 * XXX Failure here should be noted
208526947304SEvan Yan 	 */
208626947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
208726947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
208826947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
208926947304SEvan Yan 		DEBUG0("Failed to read reg property\n");
209026947304SEvan Yan 		return (PCICFG_FAILURE);
209126947304SEvan Yan 	}
209226947304SEvan Yan 
209326947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
209426947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
209526947304SEvan Yan 		/*
209626947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
209726947304SEvan Yan 		 */
209826947304SEvan Yan 		kmem_free((caddr_t)reg, length);
209926947304SEvan Yan 
210026947304SEvan Yan 		return (PCICFG_FAILURE);
210126947304SEvan Yan 	}
210226947304SEvan Yan 
210326947304SEvan Yan 	/*
210426947304SEvan Yan 	 * A single device
210526947304SEvan Yan 	 *
210626947304SEvan Yan 	 * For each "reg" property with a length, allocate memory
210726947304SEvan Yan 	 * and program the base registers.
210826947304SEvan Yan 	 */
210926947304SEvan Yan 
211026947304SEvan Yan 	/*
211126947304SEvan Yan 	 * If there is an interrupt pin set program
211226947304SEvan Yan 	 * interrupt line with default values.
211326947304SEvan Yan 	 */
211426947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
211526947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
211626947304SEvan Yan 	}
211726947304SEvan Yan 
211826947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
211926947304SEvan Yan 
212026947304SEvan Yan 	request.ra_flags |= NDI_RA_ALIGN_SIZE;
212126947304SEvan Yan 	request.ra_boundbase = 0;
212226947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
212326947304SEvan Yan 
212426947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
212526947304SEvan Yan 	offset = PCI_CONF_BASE0;
212626947304SEvan Yan 	for (i = 0; i < rcount; i++) {
212726947304SEvan Yan 		if ((reg[i].pci_size_low != 0)||
212826947304SEvan Yan 		    (reg[i].pci_size_hi != 0)) {
212926947304SEvan Yan 
213026947304SEvan Yan 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
213126947304SEvan Yan 			request.ra_len = reg[i].pci_size_low;
213226947304SEvan Yan 
213326947304SEvan Yan 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
213426947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
213526947304SEvan Yan 				request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
213626947304SEvan Yan 				/* allocate memory space from the allocator */
213726947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
213826947304SEvan Yan 				    &request, &answer, &alen,
213926947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
214026947304SEvan Yan 				    != NDI_SUCCESS) {
214126947304SEvan Yan 					DEBUG0("Failed to allocate 64b mem\n");
214226947304SEvan Yan 					kmem_free(reg, length);
214326947304SEvan Yan 					(void) pcicfg_config_teardown(&handle);
214426947304SEvan Yan 					return (PCICFG_FAILURE);
214526947304SEvan Yan 				}
214626947304SEvan Yan 				DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
214726947304SEvan Yan 				    PCICFG_HIADDR(answer),
214826947304SEvan Yan 				    PCICFG_LOADDR(answer),
214926947304SEvan Yan 				    alen);
215026947304SEvan Yan 				/* program the low word */
215126947304SEvan Yan 				pci_config_put32(handle,
215226947304SEvan Yan 				    offset, PCICFG_LOADDR(answer));
215326947304SEvan Yan 
215426947304SEvan Yan 				/* program the high word with value zero */
215526947304SEvan Yan 				pci_config_put32(handle, offset + 4,
215626947304SEvan Yan 				    PCICFG_HIADDR(answer));
215726947304SEvan Yan 
215826947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
215926947304SEvan Yan 				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
216026947304SEvan Yan 				/*
216126947304SEvan Yan 				 * currently support 32b address space
216226947304SEvan Yan 				 * assignments only.
216326947304SEvan Yan 				 */
216426947304SEvan Yan 				reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^
216526947304SEvan Yan 				    PCI_ADDR_MEM32;
216626947304SEvan Yan 
216726947304SEvan Yan 				offset += 8;
216826947304SEvan Yan 				break;
216926947304SEvan Yan 
217026947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
217126947304SEvan Yan 				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
217226947304SEvan Yan 				/* allocate memory space from the allocator */
217326947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
217426947304SEvan Yan 				    &request, &answer, &alen,
217526947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
217626947304SEvan Yan 				    != NDI_SUCCESS) {
217726947304SEvan Yan 					DEBUG0("Failed to allocate 32b mem\n");
217826947304SEvan Yan 					kmem_free(reg, length);
217926947304SEvan Yan 					(void) pcicfg_config_teardown(&handle);
218026947304SEvan Yan 					return (PCICFG_FAILURE);
218126947304SEvan Yan 				}
218226947304SEvan Yan 				DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
218326947304SEvan Yan 				    PCICFG_HIADDR(answer),
218426947304SEvan Yan 				    PCICFG_LOADDR(answer),
218526947304SEvan Yan 				    alen);
218626947304SEvan Yan 				/* program the low word */
218726947304SEvan Yan 				pci_config_put32(handle,
218826947304SEvan Yan 				    offset, PCICFG_LOADDR(answer));
218926947304SEvan Yan 
219026947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
219126947304SEvan Yan 
219226947304SEvan Yan 				offset += 4;
219326947304SEvan Yan 				break;
219426947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
219526947304SEvan Yan 				/* allocate I/O space from the allocator */
219626947304SEvan Yan 				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
219726947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
219826947304SEvan Yan 				    &request, &answer, &alen,
219926947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
220026947304SEvan Yan 				    != NDI_SUCCESS) {
220126947304SEvan Yan 					DEBUG0("Failed to allocate I/O\n");
220226947304SEvan Yan 					kmem_free(reg, length);
220326947304SEvan Yan 					(void) pcicfg_config_teardown(&handle);
220426947304SEvan Yan 					return (PCICFG_FAILURE);
220526947304SEvan Yan 				}
220626947304SEvan Yan 				DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
220726947304SEvan Yan 				    PCICFG_HIADDR(answer),
220826947304SEvan Yan 				    PCICFG_LOADDR(answer),
220926947304SEvan Yan 				    alen);
221026947304SEvan Yan 				pci_config_put32(handle,
221126947304SEvan Yan 				    offset, PCICFG_LOADDR(answer));
221226947304SEvan Yan 
221326947304SEvan Yan 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
221426947304SEvan Yan 
221526947304SEvan Yan 				offset += 4;
221626947304SEvan Yan 				break;
221726947304SEvan Yan 			default:
221826947304SEvan Yan 				DEBUG0("Unknown register type\n");
221926947304SEvan Yan 				kmem_free(reg, length);
222026947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
222126947304SEvan Yan 				return (PCICFG_FAILURE);
222226947304SEvan Yan 			} /* switch */
222326947304SEvan Yan 
222426947304SEvan Yan 			/*
222526947304SEvan Yan 			 * Now that memory locations are assigned,
222626947304SEvan Yan 			 * update the assigned address property.
222726947304SEvan Yan 			 */
222826947304SEvan Yan 
222926947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip,
223026947304SEvan Yan 			    &reg[i]) != PCICFG_SUCCESS) {
223126947304SEvan Yan 				kmem_free(reg, length);
223226947304SEvan Yan 				(void) pcicfg_config_teardown(&handle);
223326947304SEvan Yan 				return (PCICFG_FAILURE);
223426947304SEvan Yan 			}
223526947304SEvan Yan 		}
223626947304SEvan Yan 	}
223726947304SEvan Yan 
223826947304SEvan Yan 	(void) pcicfg_device_on(handle);
223926947304SEvan Yan 	kmem_free(reg, length);
224026947304SEvan Yan 
224126947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
224226947304SEvan Yan 
224326947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
224426947304SEvan Yan 	return (PCICFG_SUCCESS);
224526947304SEvan Yan }
224626947304SEvan Yan 
224726947304SEvan Yan static int
224826947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip)
224926947304SEvan Yan {
225026947304SEvan Yan 	ddi_acc_handle_t	handle;
225126947304SEvan Yan 	pci_regspec_t		*assigned;
225226947304SEvan Yan 	int			length;
225326947304SEvan Yan 	int			acount;
225426947304SEvan Yan 	int			i;
225526947304SEvan Yan 	ndi_ra_request_t	request;
225626947304SEvan Yan 	uint64_t		answer;
225726947304SEvan Yan 	uint64_t		alen;
225826947304SEvan Yan 
225926947304SEvan Yan 
226026947304SEvan Yan 	DEBUG1("%llx now under configuration\n", dip);
226126947304SEvan Yan 
226226947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
226326947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
226426947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
226526947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
226626947304SEvan Yan 		return (PCICFG_FAILURE);
226726947304SEvan Yan 	}
226826947304SEvan Yan 
226926947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
227026947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
227126947304SEvan Yan 		/*
227226947304SEvan Yan 		 * Don't forget to free up memory from ddi_getlongprop
227326947304SEvan Yan 		 */
227426947304SEvan Yan 		kmem_free((caddr_t)assigned, length);
227526947304SEvan Yan 
227626947304SEvan Yan 		return (PCICFG_FAILURE);
227726947304SEvan Yan 	}
227826947304SEvan Yan 
227926947304SEvan Yan 	/*
228026947304SEvan Yan 	 * For each "assigned-addresses" property entry with a length,
228126947304SEvan Yan 	 * call the memory allocation routines to return the
228226947304SEvan Yan 	 * resource.
228326947304SEvan Yan 	 */
228426947304SEvan Yan 	/*
228526947304SEvan Yan 	 * If there is an interrupt pin set program
228626947304SEvan Yan 	 * interrupt line with default values.
228726947304SEvan Yan 	 */
228826947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
228926947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
229026947304SEvan Yan 	}
229126947304SEvan Yan 
229226947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
229326947304SEvan Yan 
229426947304SEvan Yan 	request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */
229526947304SEvan Yan 	request.ra_boundbase = 0;
229626947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
229726947304SEvan Yan 
229826947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
229926947304SEvan Yan 	for (i = 0; i < acount; i++) {
230026947304SEvan Yan 		if ((assigned[i].pci_size_low != 0)||
230126947304SEvan Yan 		    (assigned[i].pci_size_hi != 0)) {
230226947304SEvan Yan 
230326947304SEvan Yan 			request.ra_len = assigned[i].pci_size_low;
230426947304SEvan Yan 
230526947304SEvan Yan 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
230626947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
230726947304SEvan Yan 				request.ra_addr = (uint64_t)PCICFG_LADDR(
230826947304SEvan Yan 				    assigned[i].pci_phys_low,
230926947304SEvan Yan 				    assigned[i].pci_phys_mid);
231026947304SEvan Yan 
231126947304SEvan Yan 				/* allocate memory space from the allocator */
231226947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
231326947304SEvan Yan 				    &request, &answer, &alen,
231426947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
231526947304SEvan Yan 				    != NDI_SUCCESS) {
231626947304SEvan Yan 					DEBUG0("Failed to allocate 64b mem\n");
231726947304SEvan Yan 					kmem_free(assigned, length);
231826947304SEvan Yan 					return (PCICFG_FAILURE);
231926947304SEvan Yan 				}
232026947304SEvan Yan 
232126947304SEvan Yan 				break;
232226947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
232326947304SEvan Yan 				request.ra_addr = (uint64_t)
232426947304SEvan Yan 				    assigned[i].pci_phys_low;
232526947304SEvan Yan 
232626947304SEvan Yan 				/* allocate memory space from the allocator */
232726947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
232826947304SEvan Yan 				    &request, &answer, &alen,
232926947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
233026947304SEvan Yan 				    != NDI_SUCCESS) {
233126947304SEvan Yan 					DEBUG0("Failed to allocate 32b mem\n");
233226947304SEvan Yan 					kmem_free(assigned, length);
233326947304SEvan Yan 					return (PCICFG_FAILURE);
233426947304SEvan Yan 				}
233526947304SEvan Yan 
233626947304SEvan Yan 				break;
233726947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
233826947304SEvan Yan 				request.ra_addr = (uint64_t)
233926947304SEvan Yan 				    assigned[i].pci_phys_low;
234026947304SEvan Yan 
234126947304SEvan Yan 				/* allocate I/O space from the allocator */
234226947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip),
234326947304SEvan Yan 				    &request, &answer, &alen,
234426947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
234526947304SEvan Yan 				    != NDI_SUCCESS) {
234626947304SEvan Yan 					DEBUG0("Failed to allocate I/O\n");
234726947304SEvan Yan 					kmem_free(assigned, length);
234826947304SEvan Yan 					return (PCICFG_FAILURE);
234926947304SEvan Yan 				}
235026947304SEvan Yan 
235126947304SEvan Yan 				break;
235226947304SEvan Yan 			default:
235326947304SEvan Yan 				DEBUG0("Unknown register type\n");
235426947304SEvan Yan 				kmem_free(assigned, length);
235526947304SEvan Yan 				return (PCICFG_FAILURE);
235626947304SEvan Yan 			} /* switch */
235726947304SEvan Yan 		}
235826947304SEvan Yan 	}
235926947304SEvan Yan 
236026947304SEvan Yan 	(void) pcicfg_device_on(handle);
236126947304SEvan Yan 	kmem_free(assigned, length);
236226947304SEvan Yan 
236326947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
236426947304SEvan Yan 
236526947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
236626947304SEvan Yan 	return (PCICFG_SUCCESS);
236726947304SEvan Yan }
236826947304SEvan Yan 
236926947304SEvan Yan /*
237026947304SEvan Yan  * The "dip" passed to this routine is assumed to be
237126947304SEvan Yan  * the device at the Hotplug Connection (CN). Currently it is
237226947304SEvan Yan  * assumed to be a bridge.
237326947304SEvan Yan  */
237426947304SEvan Yan static int
237526947304SEvan Yan pcicfg_allocate_chunk(dev_info_t *dip)
237626947304SEvan Yan {
237726947304SEvan Yan 	pcicfg_phdl_t		*phdl;
237826947304SEvan Yan 	ndi_ra_request_t	*mem_request;
237926947304SEvan Yan 	ndi_ra_request_t	*io_request;
238026947304SEvan Yan 	uint64_t		mem_answer;
238126947304SEvan Yan 	uint64_t		io_answer;
238226947304SEvan Yan 	int			count;
238326947304SEvan Yan 	uint64_t		alen;
238426947304SEvan Yan 
238526947304SEvan Yan 	/*
238626947304SEvan Yan 	 * This should not find an existing entry - so
238726947304SEvan Yan 	 * it will create a new one.
238826947304SEvan Yan 	 */
238926947304SEvan Yan 	phdl = pcicfg_find_phdl(dip);
239026947304SEvan Yan 	ASSERT(phdl);
239126947304SEvan Yan 
239226947304SEvan Yan 	mem_request = &phdl->mem_req;
239326947304SEvan Yan 	io_request  = &phdl->io_req;
239426947304SEvan Yan 
239526947304SEvan Yan 	/*
239626947304SEvan Yan 	 * From this point in the tree - walk the devices,
239726947304SEvan Yan 	 * The function passed in will read and "sum" up
239826947304SEvan Yan 	 * the memory and I/O requirements and put them in
239926947304SEvan Yan 	 * structure "phdl".
240026947304SEvan Yan 	 */
240126947304SEvan Yan 	ndi_devi_enter(ddi_get_parent(dip), &count);
240226947304SEvan Yan 	ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl);
240326947304SEvan Yan 	ndi_devi_exit(ddi_get_parent(dip), count);
240426947304SEvan Yan 
240526947304SEvan Yan 	if (phdl->error != PCICFG_SUCCESS) {
240626947304SEvan Yan 		DEBUG0("Failure summing resources\n");
240726947304SEvan Yan 		return (phdl->error);
240826947304SEvan Yan 	}
240926947304SEvan Yan 
241026947304SEvan Yan 	/*
241126947304SEvan Yan 	 * Call into the memory allocator with the request.
241226947304SEvan Yan 	 * Record the addresses returned in the phdl
241326947304SEvan Yan 	 */
241426947304SEvan Yan 	DEBUG1("Connector requires [0x%x] bytes of memory space\n",
241526947304SEvan Yan 	    mem_request->ra_len);
241626947304SEvan Yan 	DEBUG1("Connector requires [0x%x] bytes of I/O space\n",
241726947304SEvan Yan 	    io_request->ra_len);
241826947304SEvan Yan 
241926947304SEvan Yan 	mem_request->ra_align_mask =
242026947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
242126947304SEvan Yan 	io_request->ra_align_mask =
242226947304SEvan Yan 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
242326947304SEvan Yan 	io_request->ra_boundbase = 0;
242426947304SEvan Yan 	io_request->ra_boundlen = PCICFG_4GIG_LIMIT;
242526947304SEvan Yan 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
242626947304SEvan Yan 
242726947304SEvan Yan 	mem_request->ra_len =
242826947304SEvan Yan 	    PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
242926947304SEvan Yan 
243026947304SEvan Yan 	io_request->ra_len =
243126947304SEvan Yan 	    PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
243226947304SEvan Yan 
243326947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(dip),
243426947304SEvan Yan 	    mem_request, &mem_answer, &alen,
243526947304SEvan Yan 	    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
243626947304SEvan Yan 		DEBUG0("Failed to allocate memory\n");
243726947304SEvan Yan 		return (PCICFG_FAILURE);
243826947304SEvan Yan 	}
243926947304SEvan Yan 
244026947304SEvan Yan 	phdl->memory_base = phdl->memory_last = mem_answer;
244126947304SEvan Yan 	phdl->memory_len  = alen;
244226947304SEvan Yan 
244326947304SEvan Yan 	phdl->mem_hole.start = phdl->memory_base;
244426947304SEvan Yan 	phdl->mem_hole.len = phdl->memory_len;
244526947304SEvan Yan 	phdl->mem_hole.next = (hole_t *)NULL;
244626947304SEvan Yan 
244726947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer,
244826947304SEvan Yan 	    &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
244926947304SEvan Yan 
245026947304SEvan Yan 		DEBUG0("Failed to allocate I/O space\n");
245126947304SEvan Yan 		(void) ndi_ra_free(ddi_get_parent(dip), mem_answer,
245226947304SEvan Yan 		    alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
245326947304SEvan Yan 		phdl->memory_len = phdl->io_len = 0;
245426947304SEvan Yan 		return (PCICFG_FAILURE);
245526947304SEvan Yan 	}
245626947304SEvan Yan 
245726947304SEvan Yan 	phdl->io_base = phdl->io_last = (uint32_t)io_answer;
245826947304SEvan Yan 	phdl->io_len  = (uint32_t)alen;
245926947304SEvan Yan 
246026947304SEvan Yan 	phdl->io_hole.start = phdl->io_base;
246126947304SEvan Yan 	phdl->io_hole.len = phdl->io_len;
246226947304SEvan Yan 	phdl->io_hole.next = (hole_t *)NULL;
246326947304SEvan Yan 
246426947304SEvan Yan 	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
246526947304SEvan Yan 	    phdl->memory_base, phdl->memory_len);
246626947304SEvan Yan 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
246726947304SEvan Yan 	    phdl->io_base, phdl->io_len);
246826947304SEvan Yan 
246926947304SEvan Yan 	return (PCICFG_SUCCESS);
247026947304SEvan Yan }
247126947304SEvan Yan 
247226947304SEvan Yan #ifdef	DEBUG
247326947304SEvan Yan /*
247426947304SEvan Yan  * This function is useful in debug mode, where we can measure how
247526947304SEvan Yan  * much memory was wasted/unallocated in bridge device's domain.
247626947304SEvan Yan  */
247726947304SEvan Yan static uint64_t
247826947304SEvan Yan pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
247926947304SEvan Yan {
248026947304SEvan Yan 	uint64_t len = 0;
248126947304SEvan Yan 	uint32_t count = 0;
248226947304SEvan Yan 
248326947304SEvan Yan 	do {
248426947304SEvan Yan 		len += hole->len;
248526947304SEvan Yan 		hole = hole->next;
248626947304SEvan Yan 		count++;
248726947304SEvan Yan 	} while (hole);
248826947304SEvan Yan 	*hole_count = count;
248926947304SEvan Yan 	return (len);
249026947304SEvan Yan }
249126947304SEvan Yan #endif
249226947304SEvan Yan 
249326947304SEvan Yan /*
249426947304SEvan Yan  * This function frees data structures that hold the hole information
249526947304SEvan Yan  * which are allocated in pcicfg_alloc_hole(). This is not freeing
249626947304SEvan Yan  * any memory allocated through NDI calls.
249726947304SEvan Yan  */
249826947304SEvan Yan static void
249926947304SEvan Yan pcicfg_free_hole(hole_t *addr_hole)
250026947304SEvan Yan {
250126947304SEvan Yan 	hole_t *nhole, *hole = addr_hole->next;
250226947304SEvan Yan 
250326947304SEvan Yan 	while (hole) {
250426947304SEvan Yan 		nhole = hole->next;
250526947304SEvan Yan 		kmem_free(hole, sizeof (hole_t));
250626947304SEvan Yan 		hole = nhole;
250726947304SEvan Yan 	}
250826947304SEvan Yan }
250926947304SEvan Yan 
251026947304SEvan Yan static uint64_t
251126947304SEvan Yan pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
251226947304SEvan Yan {
251326947304SEvan Yan 	uint64_t actual_hole_start, ostart, olen;
251426947304SEvan Yan 	hole_t	*hole = addr_hole, *thole, *nhole;
251526947304SEvan Yan 
251626947304SEvan Yan 	do {
251726947304SEvan Yan 		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
251826947304SEvan Yan 		if (((actual_hole_start - hole->start) + length) <= hole->len) {
251926947304SEvan Yan 			DEBUG3("hole found. start %llx, len %llx, req=%x\n",
252026947304SEvan Yan 			    hole->start, hole->len, length);
252126947304SEvan Yan 			ostart = hole->start;
252226947304SEvan Yan 			olen = hole->len;
252326947304SEvan Yan 			/* current hole parameters adjust */
252426947304SEvan Yan 			if ((actual_hole_start - hole->start) == 0) {
252526947304SEvan Yan 				hole->start += length;
252626947304SEvan Yan 				hole->len -= length;
252726947304SEvan Yan 				if (hole->start > *alast)
252826947304SEvan Yan 					*alast = hole->start;
252926947304SEvan Yan 			} else {
253026947304SEvan Yan 				hole->len = actual_hole_start - hole->start;
253126947304SEvan Yan 				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
253226947304SEvan Yan 				    KM_SLEEP);
253326947304SEvan Yan 				nhole->start = actual_hole_start + length;
253426947304SEvan Yan 				nhole->len = (ostart + olen) - nhole->start;
253526947304SEvan Yan 				nhole->next = NULL;
253626947304SEvan Yan 				thole = hole->next;
253726947304SEvan Yan 				hole->next = nhole;
253826947304SEvan Yan 				nhole->next = thole;
253926947304SEvan Yan 				if (nhole->start > *alast)
254026947304SEvan Yan 					*alast = nhole->start;
254126947304SEvan Yan 				DEBUG2("put new hole to %llx, %llx\n",
254226947304SEvan Yan 				    nhole->start, nhole->len);
254326947304SEvan Yan 			}
254426947304SEvan Yan 			DEBUG2("adjust current hole to %llx, %llx\n",
254526947304SEvan Yan 			    hole->start, hole->len);
254626947304SEvan Yan 			break;
254726947304SEvan Yan 		}
254826947304SEvan Yan 		actual_hole_start = 0;
254926947304SEvan Yan 		hole = hole->next;
255026947304SEvan Yan 	} while (hole);
255126947304SEvan Yan 
255226947304SEvan Yan 	DEBUG1("return hole at %llx\n", actual_hole_start);
255326947304SEvan Yan 	return (actual_hole_start);
255426947304SEvan Yan }
255526947304SEvan Yan 
255626947304SEvan Yan static void
255726947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry,
255826947304SEvan Yan 	uint32_t length, uint64_t *ans)
255926947304SEvan Yan {
256026947304SEvan Yan 	uint64_t new_mem;
256126947304SEvan Yan 
256226947304SEvan Yan 	/* See if there is a hole, that can hold this request. */
256326947304SEvan Yan 	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
256426947304SEvan Yan 	    length);
256526947304SEvan Yan 	if (new_mem) {	/* if non-zero, found a hole. */
256626947304SEvan Yan 		if (ans != NULL)
256726947304SEvan Yan 			*ans = new_mem;
256826947304SEvan Yan 	} else
256926947304SEvan Yan 		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
257026947304SEvan Yan 		    length, ddi_get_name(entry->dip));
257126947304SEvan Yan }
257226947304SEvan Yan 
257326947304SEvan Yan static void
257426947304SEvan Yan pcicfg_get_io(pcicfg_phdl_t *entry,
257526947304SEvan Yan 	uint32_t length, uint32_t *ans)
257626947304SEvan Yan {
257726947304SEvan Yan 	uint32_t new_io;
257826947304SEvan Yan 	uint64_t io_last;
257926947304SEvan Yan 
258026947304SEvan Yan 	/*
258126947304SEvan Yan 	 * See if there is a hole, that can hold this request.
258226947304SEvan Yan 	 * Pass 64 bit parameters and then truncate to 32 bit.
258326947304SEvan Yan 	 */
258426947304SEvan Yan 	io_last = entry->io_last;
258526947304SEvan Yan 	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
258626947304SEvan Yan 	if (new_io) {	/* if non-zero, found a hole. */
258726947304SEvan Yan 		entry->io_last = (uint32_t)io_last;
258826947304SEvan Yan 		if (ans != NULL)
258926947304SEvan Yan 			*ans = new_io;
259026947304SEvan Yan 	} else
259126947304SEvan Yan 		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
259226947304SEvan Yan 		    length, ddi_get_name(entry->dip));
259326947304SEvan Yan }
259426947304SEvan Yan 
259526947304SEvan Yan static int
259626947304SEvan Yan pcicfg_sum_resources(dev_info_t *dip, void *hdl)
259726947304SEvan Yan {
259826947304SEvan Yan 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
259926947304SEvan Yan 	pci_regspec_t *pci_rp;
260026947304SEvan Yan 	int length;
260126947304SEvan Yan 	int rcount;
260226947304SEvan Yan 	int i;
260326947304SEvan Yan 	ndi_ra_request_t *mem_request;
260426947304SEvan Yan 	ndi_ra_request_t *io_request;
260526947304SEvan Yan 	uint8_t header_type;
260626947304SEvan Yan 	ddi_acc_handle_t handle;
260726947304SEvan Yan 
260826947304SEvan Yan 	entry->error = PCICFG_SUCCESS;
260926947304SEvan Yan 
261026947304SEvan Yan 	mem_request = &entry->mem_req;
261126947304SEvan Yan 	io_request =  &entry->io_req;
261226947304SEvan Yan 
261326947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
261426947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
261526947304SEvan Yan 		entry->error = PCICFG_FAILURE;
261626947304SEvan Yan 		return (DDI_WALK_TERMINATE);
261726947304SEvan Yan 	}
261826947304SEvan Yan 
261926947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
262026947304SEvan Yan 
262126947304SEvan Yan 	/*
262226947304SEvan Yan 	 * If its a bridge - just record the highest bus seen
262326947304SEvan Yan 	 */
262426947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
262526947304SEvan Yan 
262626947304SEvan Yan 		if (entry->highest_bus < pci_config_get8(handle,
262726947304SEvan Yan 		    PCI_BCNF_SECBUS)) {
262826947304SEvan Yan 			entry->highest_bus =
262926947304SEvan Yan 			    pci_config_get8(handle, PCI_BCNF_SECBUS);
263026947304SEvan Yan 		}
263126947304SEvan Yan 
263226947304SEvan Yan 		(void) pcicfg_config_teardown(&handle);
263326947304SEvan Yan 		entry->error = PCICFG_FAILURE;
263426947304SEvan Yan 		return (DDI_WALK_CONTINUE);
263526947304SEvan Yan 	} else {
263626947304SEvan Yan 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
263726947304SEvan Yan 		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp,
263826947304SEvan Yan 		    &length) != DDI_PROP_SUCCESS) {
263926947304SEvan Yan 			/*
264026947304SEvan Yan 			 * If one node in (the subtree of nodes)
264126947304SEvan Yan 			 * does'nt have a "reg" property fail the
264226947304SEvan Yan 			 * allocation.
264326947304SEvan Yan 			 */
264426947304SEvan Yan 			entry->memory_len = 0;
264526947304SEvan Yan 			entry->io_len = 0;
264626947304SEvan Yan 			entry->error = PCICFG_FAILURE;
264726947304SEvan Yan 			return (DDI_WALK_TERMINATE);
264826947304SEvan Yan 		}
264926947304SEvan Yan 		/*
265026947304SEvan Yan 		 * For each "reg" property with a length, add that to the
265126947304SEvan Yan 		 * total memory (or I/O) to allocate.
265226947304SEvan Yan 		 */
265326947304SEvan Yan 		rcount = length / sizeof (pci_regspec_t);
265426947304SEvan Yan 
265526947304SEvan Yan 		for (i = 0; i < rcount; i++) {
265626947304SEvan Yan 
265726947304SEvan Yan 			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
265826947304SEvan Yan 
265926947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
266026947304SEvan Yan 				mem_request->ra_len =
266126947304SEvan Yan 				    pci_rp[i].pci_size_low +
266226947304SEvan Yan 				    PCICFG_ROUND_UP(mem_request->ra_len,
266326947304SEvan Yan 				    pci_rp[i].pci_size_low);
266426947304SEvan Yan 				DEBUG1("ADDING 32 --->0x%x\n",
266526947304SEvan Yan 				    pci_rp[i].pci_size_low);
266626947304SEvan Yan 
266726947304SEvan Yan 			break;
266826947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
266926947304SEvan Yan 				mem_request->ra_len =
267026947304SEvan Yan 				    pci_rp[i].pci_size_low +
267126947304SEvan Yan 				    PCICFG_ROUND_UP(mem_request->ra_len,
267226947304SEvan Yan 				    pci_rp[i].pci_size_low);
267326947304SEvan Yan 				DEBUG1("ADDING 64 --->0x%x\n",
267426947304SEvan Yan 				    pci_rp[i].pci_size_low);
267526947304SEvan Yan 
267626947304SEvan Yan 			break;
267726947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
267826947304SEvan Yan 				io_request->ra_len =
267926947304SEvan Yan 				    pci_rp[i].pci_size_low +
268026947304SEvan Yan 				    PCICFG_ROUND_UP(io_request->ra_len,
268126947304SEvan Yan 				    pci_rp[i].pci_size_low);
268226947304SEvan Yan 				DEBUG1("ADDING I/O --->0x%x\n",
268326947304SEvan Yan 				    pci_rp[i].pci_size_low);
268426947304SEvan Yan 			break;
268526947304SEvan Yan 			default:
268626947304SEvan Yan 			    /* Config space register - not included */
268726947304SEvan Yan 			break;
268826947304SEvan Yan 			}
268926947304SEvan Yan 		}
269026947304SEvan Yan 
269126947304SEvan Yan 		/*
269226947304SEvan Yan 		 * free the memory allocated by ddi_getlongprop
269326947304SEvan Yan 		 */
269426947304SEvan Yan 		kmem_free(pci_rp, length);
269526947304SEvan Yan 
269626947304SEvan Yan 		/*
269726947304SEvan Yan 		 * continue the walk to the next sibling to sum memory
269826947304SEvan Yan 		 */
269926947304SEvan Yan 
270026947304SEvan Yan 		(void) pcicfg_config_teardown(&handle);
270126947304SEvan Yan 
270226947304SEvan Yan 		return (DDI_WALK_CONTINUE);
270326947304SEvan Yan 	}
270426947304SEvan Yan }
270526947304SEvan Yan 
270626947304SEvan Yan static int
270726947304SEvan Yan pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
270826947304SEvan Yan {
270926947304SEvan Yan 	pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl;
271026947304SEvan Yan 	pci_regspec_t *pci_ap;
271126947304SEvan Yan 	pcicfg_range_t *ranges;
271226947304SEvan Yan 	int length;
271326947304SEvan Yan 	int rcount;
271426947304SEvan Yan 	int i;
271526947304SEvan Yan 
271626947304SEvan Yan 	entry_p->error = PCICFG_SUCCESS;
271726947304SEvan Yan 
271826947304SEvan Yan 	if (dip == entry_p->dip) {
271926947304SEvan Yan 		DEBUG0("Don't include parent bridge node\n");
272026947304SEvan Yan 		return (DDI_WALK_CONTINUE);
272126947304SEvan Yan 	}
272226947304SEvan Yan 
272326947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
272426947304SEvan Yan 	    DDI_PROP_DONTPASS, "ranges",
272526947304SEvan Yan 	    (caddr_t)&ranges,  &length) != DDI_PROP_SUCCESS) {
272626947304SEvan Yan 		DEBUG0("Node doesn't have ranges\n");
272726947304SEvan Yan 		goto ap;
272826947304SEvan Yan 	}
272926947304SEvan Yan 
273026947304SEvan Yan 	rcount = length / sizeof (pcicfg_range_t);
273126947304SEvan Yan 
273226947304SEvan Yan 	for (i = 0; i < rcount; i++) {
273326947304SEvan Yan 		uint64_t base;
273426947304SEvan Yan 		uint64_t mid = ranges[i].child_mid;
273526947304SEvan Yan 		uint64_t lo = ranges[i].child_lo;
273626947304SEvan Yan 		uint64_t size = ranges[i].size_lo;
273726947304SEvan Yan 
273826947304SEvan Yan 		switch (PCI_REG_ADDR_G(ranges[i].child_hi)) {
273926947304SEvan Yan 
274026947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
274126947304SEvan Yan 			base = entry_p->memory_base;
274226947304SEvan Yan 			entry_p->memory_base = MAX(base, lo + size);
274326947304SEvan Yan 			break;
274426947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
274526947304SEvan Yan 			base = entry_p->memory_base;
274626947304SEvan Yan 			entry_p->memory_base = MAX(base,
274726947304SEvan Yan 			    PCICFG_LADDR(lo, mid) + size);
274826947304SEvan Yan 			break;
274926947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
275026947304SEvan Yan 			base = entry_p->io_base;
275126947304SEvan Yan 			entry_p->io_base = MAX(base, lo + size);
275226947304SEvan Yan 			break;
275326947304SEvan Yan 		}
275426947304SEvan Yan 	}
275526947304SEvan Yan 
275626947304SEvan Yan 	kmem_free(ranges, length);
275726947304SEvan Yan 	return (DDI_WALK_CONTINUE);
275826947304SEvan Yan 
275926947304SEvan Yan ap:	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
276026947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses",
276126947304SEvan Yan 	    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
276226947304SEvan Yan 		DEBUG0("Node doesn't have assigned-addresses\n");
276326947304SEvan Yan 		return (DDI_WALK_CONTINUE);
276426947304SEvan Yan 	}
276526947304SEvan Yan 
276626947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
276726947304SEvan Yan 
276826947304SEvan Yan 	for (i = 0; i < rcount; i++) {
276926947304SEvan Yan 
277026947304SEvan Yan 		switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
277126947304SEvan Yan 
277226947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
277326947304SEvan Yan 			if ((pci_ap[i].pci_phys_low +
277426947304SEvan Yan 			    pci_ap[i].pci_size_low) >
277526947304SEvan Yan 			    entry_p->memory_base) {
277626947304SEvan Yan 				entry_p->memory_base =
277726947304SEvan Yan 				    pci_ap[i].pci_phys_low +
277826947304SEvan Yan 				    pci_ap[i].pci_size_low;
277926947304SEvan Yan 			}
278026947304SEvan Yan 		break;
278126947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
278226947304SEvan Yan 			if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
278326947304SEvan Yan 			    pci_ap[i].pci_phys_mid) +
278426947304SEvan Yan 			    pci_ap[i].pci_size_low) >
278526947304SEvan Yan 			    entry_p->memory_base) {
278626947304SEvan Yan 				entry_p->memory_base = PCICFG_LADDR(
278726947304SEvan Yan 				    pci_ap[i].pci_phys_low,
278826947304SEvan Yan 				    pci_ap[i].pci_phys_mid) +
278926947304SEvan Yan 				    pci_ap[i].pci_size_low;
279026947304SEvan Yan 			}
279126947304SEvan Yan 		break;
279226947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
279326947304SEvan Yan 			if ((pci_ap[i].pci_phys_low +
279426947304SEvan Yan 			    pci_ap[i].pci_size_low) >
279526947304SEvan Yan 			    entry_p->io_base) {
279626947304SEvan Yan 				entry_p->io_base =
279726947304SEvan Yan 				    pci_ap[i].pci_phys_low +
279826947304SEvan Yan 				    pci_ap[i].pci_size_low;
279926947304SEvan Yan 			}
280026947304SEvan Yan 		break;
280126947304SEvan Yan 		}
280226947304SEvan Yan 	}
280326947304SEvan Yan 
280426947304SEvan Yan 	/*
280526947304SEvan Yan 	 * free the memory allocated by ddi_getlongprop
280626947304SEvan Yan 	 */
280726947304SEvan Yan 	kmem_free(pci_ap, length);
280826947304SEvan Yan 
280926947304SEvan Yan 	/*
281026947304SEvan Yan 	 * continue the walk to the next sibling to sum memory
281126947304SEvan Yan 	 */
281226947304SEvan Yan 	return (DDI_WALK_CONTINUE);
281326947304SEvan Yan }
281426947304SEvan Yan 
281526947304SEvan Yan static int
281626947304SEvan Yan pcicfg_free_bridge_resources(dev_info_t *dip)
281726947304SEvan Yan {
281826947304SEvan Yan 	pcicfg_range_t		*ranges;
281926947304SEvan Yan 	uint_t			*bus;
282026947304SEvan Yan 	int			k;
282126947304SEvan Yan 	int			length;
282226947304SEvan Yan 	int			i;
282326947304SEvan Yan 
282426947304SEvan Yan 
282526947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
282626947304SEvan Yan 	    DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
282726947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
282826947304SEvan Yan 		DEBUG0("Failed to read ranges property\n");
282926947304SEvan Yan 		if (ddi_get_child(dip)) {
283026947304SEvan Yan 			cmn_err(CE_WARN, "No ranges property found for %s",
283126947304SEvan Yan 			    ddi_get_name(dip));
283226947304SEvan Yan 			/*
283326947304SEvan Yan 			 * strictly speaking, we can check for children with
283426947304SEvan Yan 			 * assigned-addresses but for now it is better to
283526947304SEvan Yan 			 * be conservative and assume that if there are child
283626947304SEvan Yan 			 * nodes, then they do consume PCI memory or IO
283726947304SEvan Yan 			 * resources, Hence return failure.
283826947304SEvan Yan 			 */
283926947304SEvan Yan 			return (PCICFG_FAILURE);
284026947304SEvan Yan 		}
284126947304SEvan Yan 		length = 0;
284226947304SEvan Yan 
284326947304SEvan Yan 	}
284426947304SEvan Yan 
284526947304SEvan Yan 	for (i = 0; i < length / sizeof (pcicfg_range_t); i++) {
284626947304SEvan Yan 		if (ranges[i].size_lo != 0 ||
284726947304SEvan Yan 		    ranges[i].size_hi != 0) {
284826947304SEvan Yan 			switch (ranges[i].parent_hi & PCI_REG_ADDR_M) {
284926947304SEvan Yan 				case PCI_ADDR_IO:
285026947304SEvan Yan 					DEBUG2("Free I/O    "
285126947304SEvan Yan 					    "base/length = [0x%x]/[0x%x]\n",
285226947304SEvan Yan 					    ranges[i].child_lo,
285326947304SEvan Yan 					    ranges[i].size_lo);
285426947304SEvan Yan 					if (ndi_ra_free(ddi_get_parent(dip),
285526947304SEvan Yan 					    (uint64_t)ranges[i].child_lo,
285626947304SEvan Yan 					    (uint64_t)ranges[i].size_lo,
285726947304SEvan Yan 					    NDI_RA_TYPE_IO, NDI_RA_PASS)
285826947304SEvan Yan 					    != NDI_SUCCESS) {
285926947304SEvan Yan 						DEBUG0("Trouble freeing "
286026947304SEvan Yan 						    "PCI i/o space\n");
286126947304SEvan Yan 						kmem_free(ranges, length);
286226947304SEvan Yan 						return (PCICFG_FAILURE);
286326947304SEvan Yan 					}
286426947304SEvan Yan 				break;
286526947304SEvan Yan 				case PCI_ADDR_MEM32:
286626947304SEvan Yan 				case PCI_ADDR_MEM64:
286726947304SEvan Yan 					DEBUG3("Free Memory base/length = "
286826947304SEvan Yan 					    "[0x%x.%x]/[0x%x]\n",
286926947304SEvan Yan 					    ranges[i].child_mid,
287026947304SEvan Yan 					    ranges[i].child_lo,
287126947304SEvan Yan 					    ranges[i].size_lo)
287226947304SEvan Yan 					if (ndi_ra_free(ddi_get_parent(dip),
287326947304SEvan Yan 					    PCICFG_LADDR(ranges[i].child_lo,
287426947304SEvan Yan 					    ranges[i].child_mid),
287526947304SEvan Yan 					    (uint64_t)ranges[i].size_lo,
287626947304SEvan Yan 					    NDI_RA_TYPE_MEM, NDI_RA_PASS)
287726947304SEvan Yan 					    != NDI_SUCCESS) {
287826947304SEvan Yan 						DEBUG0("Trouble freeing "
287926947304SEvan Yan 						    "PCI memory space\n");
288026947304SEvan Yan 						kmem_free(ranges, length);
288126947304SEvan Yan 						return (PCICFG_FAILURE);
288226947304SEvan Yan 					}
288326947304SEvan Yan 				break;
288426947304SEvan Yan 				default:
288526947304SEvan Yan 					DEBUG0("Unknown memory space\n");
288626947304SEvan Yan 				break;
288726947304SEvan Yan 			}
288826947304SEvan Yan 		}
288926947304SEvan Yan 	}
289026947304SEvan Yan 
289126947304SEvan Yan 	if (length)
289226947304SEvan Yan 		kmem_free(ranges, length);
289326947304SEvan Yan 
289426947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
289526947304SEvan Yan 	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
289626947304SEvan Yan 	    &k) != DDI_PROP_SUCCESS) {
289726947304SEvan Yan 		DEBUG0("Failed to read bus-range property\n");
289826947304SEvan Yan 		return (PCICFG_FAILURE);
289926947304SEvan Yan 	}
290026947304SEvan Yan 
290126947304SEvan Yan 	DEBUG2("Need to free bus [%d] range [%d]\n",
290226947304SEvan Yan 	    bus[0], bus[1] - bus[0] + 1);
290326947304SEvan Yan 
290426947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip),
290526947304SEvan Yan 	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
290626947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
290726947304SEvan Yan 		/*EMPTY*/
290826947304SEvan Yan 		DEBUG0("Failed to free a bus number\n");
290926947304SEvan Yan 	}
291026947304SEvan Yan 	/*
291126947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
291226947304SEvan Yan 	 */
291326947304SEvan Yan 	kmem_free((caddr_t)bus, k);
291426947304SEvan Yan 
291526947304SEvan Yan 	return (PCICFG_SUCCESS);
291626947304SEvan Yan }
291726947304SEvan Yan 
291826947304SEvan Yan static int
291926947304SEvan Yan pcicfg_free_device_resources(dev_info_t *dip, pcicfg_flags_t flags)
292026947304SEvan Yan {
292126947304SEvan Yan 	pci_regspec_t *assigned;
292226947304SEvan Yan 
292326947304SEvan Yan 	int length;
292426947304SEvan Yan 	int acount;
292526947304SEvan Yan 	int i;
292626947304SEvan Yan 
292726947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
292826947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
292926947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
293026947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
293126947304SEvan Yan 		return (PCICFG_FAILURE);
293226947304SEvan Yan 	}
293326947304SEvan Yan 
293426947304SEvan Yan 	/*
293526947304SEvan Yan 	 * For each "assigned-addresses" property entry with a length,
293626947304SEvan Yan 	 * call the memory allocation routines to return the
293726947304SEvan Yan 	 * resource.
293826947304SEvan Yan 	 */
293926947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
294026947304SEvan Yan 	for (i = 0; i < acount; i++) {
294126947304SEvan Yan 		/*
294226947304SEvan Yan 		 * Workaround for Devconf (x86) bug to skip extra entries
294326947304SEvan Yan 		 * beyond the PCI_CONF_BASE5 offset. But we want to free up
294426947304SEvan Yan 		 * any memory for expansion roms if allocated.
294526947304SEvan Yan 		 */
294626947304SEvan Yan 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) &&
294726947304SEvan Yan 		    (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM))
294826947304SEvan Yan 			break;
294926947304SEvan Yan 
295026947304SEvan Yan 		if (pcicfg_free_resource(dip, assigned[i], flags)) {
295126947304SEvan Yan 			DEBUG1("pcicfg_free_device_resources - Trouble freeing "
295226947304SEvan Yan 			    "%x\n", assigned[i].pci_phys_hi);
295326947304SEvan Yan 			/*
295426947304SEvan Yan 			 * Don't forget to free up memory from ddi_getlongprop
295526947304SEvan Yan 			 */
295626947304SEvan Yan 			kmem_free((caddr_t)assigned, length);
295726947304SEvan Yan 
295826947304SEvan Yan 			return (PCICFG_FAILURE);
295926947304SEvan Yan 		}
296026947304SEvan Yan 	}
296126947304SEvan Yan 	kmem_free(assigned, length);
296226947304SEvan Yan 	return (PCICFG_SUCCESS);
296326947304SEvan Yan }
296426947304SEvan Yan 
296526947304SEvan Yan static int
296626947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
296726947304SEvan Yan {
296826947304SEvan Yan 	ddi_acc_handle_t handle;
296926947304SEvan Yan 	uint8_t header_type;
297026947304SEvan Yan 
297126947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
297226947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
297326947304SEvan Yan 		return (PCICFG_FAILURE);
297426947304SEvan Yan 	}
297526947304SEvan Yan 
297626947304SEvan Yan 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
297726947304SEvan Yan 
297826947304SEvan Yan 	(void) pci_config_teardown(&handle);
297926947304SEvan Yan 
298026947304SEvan Yan 	/*
298126947304SEvan Yan 	 * A different algorithm is used for bridges and leaf devices.
298226947304SEvan Yan 	 */
298326947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
298426947304SEvan Yan 		/*
298526947304SEvan Yan 		 * We only support readonly probing for leaf devices.
298626947304SEvan Yan 		 */
298726947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
298826947304SEvan Yan 			return (PCICFG_FAILURE);
298926947304SEvan Yan 
299026947304SEvan Yan 		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
299126947304SEvan Yan 			DEBUG0("Failed freeing up bridge resources\n");
299226947304SEvan Yan 			return (PCICFG_FAILURE);
299326947304SEvan Yan 		}
299426947304SEvan Yan 	} else {
299526947304SEvan Yan 		if (pcicfg_free_device_resources(dip, flags)
299626947304SEvan Yan 		    != PCICFG_SUCCESS) {
299726947304SEvan Yan 			DEBUG0("Failed freeing up device resources\n");
299826947304SEvan Yan 			return (PCICFG_FAILURE);
299926947304SEvan Yan 		}
300026947304SEvan Yan 	}
300126947304SEvan Yan 	return (PCICFG_SUCCESS);
300226947304SEvan Yan }
300326947304SEvan Yan 
300426947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES
300526947304SEvan Yan static char *
300626947304SEvan Yan pcicfg_get_class_name(uint32_t classcode)
300726947304SEvan Yan {
300826947304SEvan Yan 	struct pcicfg_name_entry *ptr;
300926947304SEvan Yan 
301026947304SEvan Yan 	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
301126947304SEvan Yan 		if (ptr->class_code == classcode) {
301226947304SEvan Yan 			return (ptr->name);
301326947304SEvan Yan 		}
301426947304SEvan Yan 	}
301526947304SEvan Yan 	return (NULL);
301626947304SEvan Yan }
301726947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */
301826947304SEvan Yan 
301926947304SEvan Yan static dev_info_t *
302026947304SEvan Yan pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
302126947304SEvan Yan {
302226947304SEvan Yan 	struct pcicfg_find_ctrl ctrl;
302326947304SEvan Yan 	int count;
302426947304SEvan Yan 
302526947304SEvan Yan 	ctrl.device = device;
302626947304SEvan Yan 	ctrl.function = function;
302726947304SEvan Yan 	ctrl.dip = NULL;
302826947304SEvan Yan 
302926947304SEvan Yan 	ndi_devi_enter(dip, &count);
303026947304SEvan Yan 	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
303126947304SEvan Yan 	ndi_devi_exit(dip, count);
303226947304SEvan Yan 
303326947304SEvan Yan 	return (ctrl.dip);
303426947304SEvan Yan }
303526947304SEvan Yan 
303626947304SEvan Yan static int
303726947304SEvan Yan pcicfg_match_dev(dev_info_t *dip, void *hdl)
303826947304SEvan Yan {
303926947304SEvan Yan 	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
304026947304SEvan Yan 	pci_regspec_t *pci_rp;
304126947304SEvan Yan 	int length;
304226947304SEvan Yan 	int pci_dev;
304326947304SEvan Yan 	int pci_func;
304426947304SEvan Yan 
304526947304SEvan Yan 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
304626947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
304726947304SEvan Yan 	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
304826947304SEvan Yan 		ctrl->dip = NULL;
304926947304SEvan Yan 		return (DDI_WALK_TERMINATE);
305026947304SEvan Yan 	}
305126947304SEvan Yan 
305226947304SEvan Yan 	/* get the PCI device address info */
305326947304SEvan Yan 	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
305426947304SEvan Yan 	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
305526947304SEvan Yan 
305626947304SEvan Yan 	/*
305726947304SEvan Yan 	 * free the memory allocated by ddi_prop_lookup_int_array
305826947304SEvan Yan 	 */
305926947304SEvan Yan 	ddi_prop_free(pci_rp);
306026947304SEvan Yan 
306126947304SEvan Yan 
306226947304SEvan Yan 	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
306326947304SEvan Yan 		/* found the match for the specified device address */
306426947304SEvan Yan 		ctrl->dip = dip;
306526947304SEvan Yan 		return (DDI_WALK_TERMINATE);
306626947304SEvan Yan 	}
306726947304SEvan Yan 
306826947304SEvan Yan 	/*
306926947304SEvan Yan 	 * continue the walk to the next sibling to look for a match.
307026947304SEvan Yan 	 */
307126947304SEvan Yan 	return (DDI_WALK_PRUNECHILD);
307226947304SEvan Yan }
307326947304SEvan Yan 
307426947304SEvan Yan static int
307526947304SEvan Yan pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
307626947304SEvan Yan {
307726947304SEvan Yan 	int		alen;
307826947304SEvan Yan 	pci_regspec_t	*assigned;
307926947304SEvan Yan 	caddr_t		newreg;
308026947304SEvan Yan 	uint_t		status;
308126947304SEvan Yan 
308226947304SEvan Yan 	DEBUG0("pcicfg_update_assigned_prop()\n");
308326947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
308426947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &alen);
308526947304SEvan Yan 	switch (status) {
308626947304SEvan Yan 		case DDI_PROP_SUCCESS:
308726947304SEvan Yan 		break;
308826947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
308926947304SEvan Yan 			DEBUG0("no memory for assigned-addresses property\n");
309026947304SEvan Yan 			return (PCICFG_FAILURE);
309126947304SEvan Yan 		default:
309226947304SEvan Yan 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
309326947304SEvan Yan 			    "assigned-addresses", (int *)newone,
309426947304SEvan Yan 			    sizeof (*newone)/sizeof (int));
309526947304SEvan Yan 
309626947304SEvan Yan 			(void) pcicfg_dump_assigned(dip);
309726947304SEvan Yan 
309826947304SEvan Yan 			return (PCICFG_SUCCESS);
309926947304SEvan Yan 	}
310026947304SEvan Yan 
310126947304SEvan Yan 	/*
310226947304SEvan Yan 	 * Allocate memory for the existing
310326947304SEvan Yan 	 * assigned-addresses(s) plus one and then
310426947304SEvan Yan 	 * build it.
310526947304SEvan Yan 	 */
310626947304SEvan Yan 
310726947304SEvan Yan 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
310826947304SEvan Yan 
310926947304SEvan Yan 	bcopy(assigned, newreg, alen);
311026947304SEvan Yan 	bcopy(newone, newreg + alen, sizeof (*newone));
311126947304SEvan Yan 
311226947304SEvan Yan 	/*
311326947304SEvan Yan 	 * Write out the new "assigned-addresses" spec
311426947304SEvan Yan 	 */
311526947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
311626947304SEvan Yan 	    "assigned-addresses", (int *)newreg,
311726947304SEvan Yan 	    (alen + sizeof (*newone))/sizeof (int));
311826947304SEvan Yan 
311926947304SEvan Yan 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
312026947304SEvan Yan 
312126947304SEvan Yan 	/*
312226947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
312326947304SEvan Yan 	 */
312426947304SEvan Yan 	kmem_free((caddr_t)assigned, alen);
312526947304SEvan Yan 
312626947304SEvan Yan 	(void) pcicfg_dump_assigned(dip);
312726947304SEvan Yan 
312826947304SEvan Yan 	return (PCICFG_SUCCESS);
312926947304SEvan Yan }
313026947304SEvan Yan static int
313126947304SEvan Yan pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition)
313226947304SEvan Yan {
313326947304SEvan Yan 	int		rlen;
313426947304SEvan Yan 	pcicfg_range_t	*ranges;
313526947304SEvan Yan 	caddr_t		newreg;
313626947304SEvan Yan 	uint_t		status;
313726947304SEvan Yan 
313826947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
313926947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen);
314026947304SEvan Yan 
314126947304SEvan Yan 
314226947304SEvan Yan 	switch (status) {
314326947304SEvan Yan 		case DDI_PROP_SUCCESS:
314426947304SEvan Yan 		break;
314526947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
314626947304SEvan Yan 			DEBUG0("ranges present, but unable to get memory\n");
314726947304SEvan Yan 			return (PCICFG_FAILURE);
314826947304SEvan Yan 		default:
314926947304SEvan Yan 			DEBUG0("no ranges property - creating one\n");
315026947304SEvan Yan 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
315126947304SEvan Yan 			    dip, "ranges", (int *)addition,
315226947304SEvan Yan 			    sizeof (pcicfg_range_t)/sizeof (int))
315326947304SEvan Yan 			    != DDI_SUCCESS) {
315426947304SEvan Yan 				DEBUG0("Did'nt create ranges property\n");
315526947304SEvan Yan 				return (PCICFG_FAILURE);
315626947304SEvan Yan 			}
315726947304SEvan Yan 			return (PCICFG_SUCCESS);
315826947304SEvan Yan 	}
315926947304SEvan Yan 
316026947304SEvan Yan 	/*
316126947304SEvan Yan 	 * Allocate memory for the existing reg(s) plus one and then
316226947304SEvan Yan 	 * build it.
316326947304SEvan Yan 	 */
316426947304SEvan Yan 	newreg = kmem_zalloc(rlen + sizeof (pcicfg_range_t), KM_SLEEP);
316526947304SEvan Yan 
316626947304SEvan Yan 	bcopy(ranges, newreg, rlen);
316726947304SEvan Yan 	bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t));
316826947304SEvan Yan 
316926947304SEvan Yan 	/*
317026947304SEvan Yan 	 * Write out the new "ranges" property
317126947304SEvan Yan 	 */
317226947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
317326947304SEvan Yan 	    dip, "ranges", (int *)newreg,
317426947304SEvan Yan 	    (rlen + sizeof (pcicfg_range_t))/sizeof (int));
317526947304SEvan Yan 
317626947304SEvan Yan 	kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t));
317726947304SEvan Yan 
317826947304SEvan Yan 	kmem_free((caddr_t)ranges, rlen);
317926947304SEvan Yan 
318026947304SEvan Yan 	return (PCICFG_SUCCESS);
318126947304SEvan Yan }
318226947304SEvan Yan 
318326947304SEvan Yan static int
318426947304SEvan Yan pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
318526947304SEvan Yan {
318626947304SEvan Yan 	int		rlen;
318726947304SEvan Yan 	pci_regspec_t	*reg;
318826947304SEvan Yan 	caddr_t		newreg;
318926947304SEvan Yan 	uint32_t	hiword;
319026947304SEvan Yan 	pci_regspec_t	addition;
319126947304SEvan Yan 	uint32_t	size;
319226947304SEvan Yan 	uint_t		status;
319326947304SEvan Yan 
319426947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
319526947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
319626947304SEvan Yan 
319726947304SEvan Yan 	switch (status) {
319826947304SEvan Yan 		case DDI_PROP_SUCCESS:
319926947304SEvan Yan 		break;
320026947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
320126947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
320226947304SEvan Yan 			return (PCICFG_FAILURE);
320326947304SEvan Yan 		default:
320426947304SEvan Yan 			DEBUG0("no reg property\n");
320526947304SEvan Yan 			return (PCICFG_FAILURE);
320626947304SEvan Yan 	}
320726947304SEvan Yan 
320826947304SEvan Yan 	/*
320926947304SEvan Yan 	 * Allocate memory for the existing reg(s) plus one and then
321026947304SEvan Yan 	 * build it.
321126947304SEvan Yan 	 */
321226947304SEvan Yan 	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
321326947304SEvan Yan 
321426947304SEvan Yan 	/*
321526947304SEvan Yan 	 * Build the regspec, then add it to the existing one(s)
321626947304SEvan Yan 	 */
321726947304SEvan Yan 
321826947304SEvan Yan 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
321926947304SEvan Yan 	    PCI_REG_DEV_G(reg->pci_phys_hi),
322026947304SEvan Yan 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
322126947304SEvan Yan 
322226947304SEvan Yan 	if (reg_offset == PCI_CONF_ROM) {
322326947304SEvan Yan 		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
322426947304SEvan Yan 		hiword |= PCI_ADDR_MEM32;
322526947304SEvan Yan 	} else {
322626947304SEvan Yan 		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
322726947304SEvan Yan 
322826947304SEvan Yan 		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
322926947304SEvan Yan 			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
323026947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
323126947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & regvalue)
323226947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
323326947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
323426947304SEvan Yan 			}
323526947304SEvan Yan 		} else {
323626947304SEvan Yan 			hiword |= PCI_ADDR_IO;
323726947304SEvan Yan 		}
323826947304SEvan Yan 	}
323926947304SEvan Yan 
324026947304SEvan Yan 	addition.pci_phys_hi = hiword;
324126947304SEvan Yan 	addition.pci_phys_mid = 0;
324226947304SEvan Yan 	addition.pci_phys_low = 0;
324326947304SEvan Yan 	addition.pci_size_hi = 0;
324426947304SEvan Yan 	addition.pci_size_low = size;
324526947304SEvan Yan 
324626947304SEvan Yan 	bcopy(reg, newreg, rlen);
324726947304SEvan Yan 	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
324826947304SEvan Yan 
324926947304SEvan Yan 	/*
325026947304SEvan Yan 	 * Write out the new "reg" property
325126947304SEvan Yan 	 */
325226947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
325326947304SEvan Yan 	    dip, "reg", (int *)newreg,
325426947304SEvan Yan 	    (rlen + sizeof (pci_regspec_t))/sizeof (int));
325526947304SEvan Yan 
325626947304SEvan Yan 	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
325726947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
325826947304SEvan Yan 
325926947304SEvan Yan 	return (PCICFG_SUCCESS);
326026947304SEvan Yan }
326126947304SEvan Yan static int
326226947304SEvan Yan pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone)
326326947304SEvan Yan {
326426947304SEvan Yan 	int		alen;
326526947304SEvan Yan 	pci_regspec_t	*avail_p;
326626947304SEvan Yan 	caddr_t		new_avail;
326726947304SEvan Yan 	uint_t		status;
326826947304SEvan Yan 
326926947304SEvan Yan 	DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n",
327026947304SEvan Yan 	    newone->pci_phys_low, newone->pci_size_low);
327126947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
327226947304SEvan Yan 	    "available", (caddr_t)&avail_p, &alen);
327326947304SEvan Yan 	switch (status) {
327426947304SEvan Yan 		case DDI_PROP_SUCCESS:
327526947304SEvan Yan 			break;
327626947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
327726947304SEvan Yan 			DEBUG0("no memory for available property\n");
327826947304SEvan Yan 			return (PCICFG_FAILURE);
327926947304SEvan Yan 		default:
328026947304SEvan Yan 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
328126947304SEvan Yan 			    "available", (int *)newone,
328226947304SEvan Yan 			    sizeof (*newone)/sizeof (int));
328326947304SEvan Yan 
328426947304SEvan Yan 			return (PCICFG_SUCCESS);
328526947304SEvan Yan 	}
328626947304SEvan Yan 
328726947304SEvan Yan 	/*
328826947304SEvan Yan 	 * Allocate memory for the existing available plus one and then
328926947304SEvan Yan 	 * build it.
329026947304SEvan Yan 	 */
329126947304SEvan Yan 	new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
329226947304SEvan Yan 
329326947304SEvan Yan 	bcopy(avail_p, new_avail, alen);
329426947304SEvan Yan 	bcopy(newone, new_avail + alen, sizeof (*newone));
329526947304SEvan Yan 
329626947304SEvan Yan 	/* Write out the new "available" spec */
329726947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
329826947304SEvan Yan 	    "available", (int *)new_avail,
329926947304SEvan Yan 	    (alen + sizeof (*newone))/sizeof (int));
330026947304SEvan Yan 
330126947304SEvan Yan 	kmem_free((caddr_t)new_avail, alen+sizeof (*newone));
330226947304SEvan Yan 
330326947304SEvan Yan 	/* Don't forget to free up memory from ddi_getlongprop */
330426947304SEvan Yan 	kmem_free((caddr_t)avail_p, alen);
330526947304SEvan Yan 
330626947304SEvan Yan 	return (PCICFG_SUCCESS);
330726947304SEvan Yan }
330826947304SEvan Yan 
330926947304SEvan Yan static int
331026947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
331126947304SEvan Yan     uint32_t base, uint32_t base_hi, uint_t reg_offset)
331226947304SEvan Yan {
331326947304SEvan Yan 	int		rlen;
331426947304SEvan Yan 	pci_regspec_t	*reg;
331526947304SEvan Yan 	uint32_t	hiword;
331626947304SEvan Yan 	pci_regspec_t	addition;
331726947304SEvan Yan 	uint_t		status;
331826947304SEvan Yan 
331926947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
332026947304SEvan Yan 	    "reg", (caddr_t)&reg, &rlen);
332126947304SEvan Yan 
332226947304SEvan Yan 	switch (status) {
332326947304SEvan Yan 		case DDI_PROP_SUCCESS:
332426947304SEvan Yan 		break;
332526947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
332626947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
332726947304SEvan Yan 			return (PCICFG_FAILURE);
332826947304SEvan Yan 		default:
332926947304SEvan Yan 			/*
333026947304SEvan Yan 			 * Since the config space "reg" entry should have been
333126947304SEvan Yan 			 * created, we expect a "reg" property already
333226947304SEvan Yan 			 * present here.
333326947304SEvan Yan 			 */
333426947304SEvan Yan 			DEBUG0("no reg property\n");
333526947304SEvan Yan 			return (PCICFG_FAILURE);
333626947304SEvan Yan 	}
333726947304SEvan Yan 
333826947304SEvan Yan 	/*
333926947304SEvan Yan 	 * Build the regspec, then add it to the existing one(s)
334026947304SEvan Yan 	 */
334126947304SEvan Yan 
334226947304SEvan Yan 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
334326947304SEvan Yan 	    PCI_REG_DEV_G(reg->pci_phys_hi),
334426947304SEvan Yan 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
334526947304SEvan Yan 
334626947304SEvan Yan 	hiword |= PCI_REG_REL_M;
334726947304SEvan Yan 
334826947304SEvan Yan 	if (reg_offset == PCI_CONF_ROM) {
334926947304SEvan Yan 		hiword |= PCI_ADDR_MEM32;
335026947304SEvan Yan 
335126947304SEvan Yan 		base = PCI_BASE_ROM_ADDR_M & base;
335226947304SEvan Yan 	} else {
335326947304SEvan Yan 		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
335426947304SEvan Yan 			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
335526947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
335626947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & base)
335726947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
335826947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
335926947304SEvan Yan 			}
336026947304SEvan Yan 
336126947304SEvan Yan 			if (base & PCI_BASE_PREF_M)
336226947304SEvan Yan 				hiword |= PCI_REG_PF_M;
336326947304SEvan Yan 
336426947304SEvan Yan 			base = PCI_BASE_M_ADDR_M & base;
336526947304SEvan Yan 		} else {
336626947304SEvan Yan 			hiword |= PCI_ADDR_IO;
336726947304SEvan Yan 
336826947304SEvan Yan 			base = PCI_BASE_IO_ADDR_M & base;
336926947304SEvan Yan 			base_hi = 0;
337026947304SEvan Yan 		}
337126947304SEvan Yan 	}
337226947304SEvan Yan 
337326947304SEvan Yan 	addition.pci_phys_hi = hiword;
337426947304SEvan Yan 	addition.pci_phys_mid = base_hi;
337526947304SEvan Yan 	addition.pci_phys_low = base;
337626947304SEvan Yan 	addition.pci_size_hi = 0;
337726947304SEvan Yan 	addition.pci_size_low = size;
337826947304SEvan Yan 
337926947304SEvan Yan 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
338026947304SEvan Yan 
338126947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
338226947304SEvan Yan 
338326947304SEvan Yan 	return (pcicfg_update_assigned_prop(dip, &addition));
338426947304SEvan Yan }
338526947304SEvan Yan 
338626947304SEvan Yan static void
338726947304SEvan Yan pcicfg_device_on(ddi_acc_handle_t config_handle)
338826947304SEvan Yan {
338926947304SEvan Yan 	/*
339026947304SEvan Yan 	 * Enable memory, IO, and bus mastership
339126947304SEvan Yan 	 * XXX should we enable parity, SERR#,
339226947304SEvan Yan 	 * fast back-to-back, and addr. stepping?
339326947304SEvan Yan 	 */
339426947304SEvan Yan 	pci_config_put16(config_handle, PCI_CONF_COMM,
339526947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
339626947304SEvan Yan }
339726947304SEvan Yan 
339826947304SEvan Yan static void
339926947304SEvan Yan pcicfg_device_off(ddi_acc_handle_t config_handle)
340026947304SEvan Yan {
340126947304SEvan Yan 	/*
340226947304SEvan Yan 	 * Disable I/O and memory traffic through the bridge
340326947304SEvan Yan 	 */
340426947304SEvan Yan 	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
340526947304SEvan Yan }
340626947304SEvan Yan 
340726947304SEvan Yan /*
340826947304SEvan Yan  * Setup the basic 1275 properties based on information found in the config
340926947304SEvan Yan  * header of the PCI device
341026947304SEvan Yan  */
341126947304SEvan Yan static int
341226947304SEvan Yan pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
341326947304SEvan Yan 	uint8_t pcie_dev)
341426947304SEvan Yan {
341526947304SEvan Yan 	int ret;
341626947304SEvan Yan 	uint16_t val, cap_ptr;
341726947304SEvan Yan 	uint32_t wordval;
341826947304SEvan Yan 	uint8_t byteval;
341926947304SEvan Yan 
342026947304SEvan Yan 	/* These two exists only for non-bridges */
342126947304SEvan Yan 	if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
342226947304SEvan Yan 	    & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
342326947304SEvan Yan 		byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
342426947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
342526947304SEvan Yan 		    "min-grant", byteval)) != DDI_SUCCESS) {
342626947304SEvan Yan 			return (ret);
342726947304SEvan Yan 		}
342826947304SEvan Yan 
342926947304SEvan Yan 		byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
343026947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
343126947304SEvan Yan 		    "max-latency", byteval)) != DDI_SUCCESS) {
343226947304SEvan Yan 			return (ret);
343326947304SEvan Yan 		}
343426947304SEvan Yan 	}
343526947304SEvan Yan 
343626947304SEvan Yan 	/*
343726947304SEvan Yan 	 * These should always exist and have the value of the
343826947304SEvan Yan 	 * corresponding register value
343926947304SEvan Yan 	 */
344026947304SEvan Yan 	val = pci_config_get16(config_handle, PCI_CONF_VENID);
344126947304SEvan Yan 
344226947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
344326947304SEvan Yan 	    "vendor-id", val)) != DDI_SUCCESS) {
344426947304SEvan Yan 		return (ret);
344526947304SEvan Yan 	}
344626947304SEvan Yan 	val = pci_config_get16(config_handle, PCI_CONF_DEVID);
344726947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
344826947304SEvan Yan 	    "device-id", val)) != DDI_SUCCESS) {
344926947304SEvan Yan 		return (ret);
345026947304SEvan Yan 	}
345126947304SEvan Yan 	byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
345226947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
345326947304SEvan Yan 	    "revision-id", byteval)) != DDI_SUCCESS) {
345426947304SEvan Yan 		return (ret);
345526947304SEvan Yan 	}
345626947304SEvan Yan 
345726947304SEvan Yan 	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
345826947304SEvan Yan 	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
345926947304SEvan Yan 
346026947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
346126947304SEvan Yan 	    "class-code", wordval)) != DDI_SUCCESS) {
346226947304SEvan Yan 		return (ret);
346326947304SEvan Yan 	}
346426947304SEvan Yan 	/* devsel-speed starts at the 9th bit */
346526947304SEvan Yan 	val = (pci_config_get16(config_handle,
346626947304SEvan Yan 	    PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9;
346726947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
346826947304SEvan Yan 	    "devsel-speed", val)) != DDI_SUCCESS) {
346926947304SEvan Yan 		return (ret);
347026947304SEvan Yan 	}
347126947304SEvan Yan 
347226947304SEvan Yan 	/*
347326947304SEvan Yan 	 * The next three are bits set in the status register.  The property is
347426947304SEvan Yan 	 * present (but with no value other than its own existence) if the bit
347526947304SEvan Yan 	 * is set, non-existent otherwise
347626947304SEvan Yan 	 */
347726947304SEvan Yan 	if ((!pcie_dev) &&
347826947304SEvan Yan 	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
347926947304SEvan Yan 	    PCI_STAT_FBBC)) {
348026947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
348126947304SEvan Yan 		    "fast-back-to-back", 0)) != DDI_SUCCESS) {
348226947304SEvan Yan 			return (ret);
348326947304SEvan Yan 		}
348426947304SEvan Yan 	}
348526947304SEvan Yan 	if ((!pcie_dev) &&
348626947304SEvan Yan 	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
348726947304SEvan Yan 	    PCI_STAT_66MHZ)) {
348826947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
348926947304SEvan Yan 		    "66mhz-capable", 0)) != DDI_SUCCESS) {
349026947304SEvan Yan 			return (ret);
349126947304SEvan Yan 		}
349226947304SEvan Yan 	}
349326947304SEvan Yan 	if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
349426947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
349526947304SEvan Yan 		    "udf-supported", 0)) != DDI_SUCCESS) {
349626947304SEvan Yan 			return (ret);
349726947304SEvan Yan 		}
349826947304SEvan Yan 	}
349926947304SEvan Yan 
350026947304SEvan Yan 	/*
350126947304SEvan Yan 	 * These next three are optional and are not present
350226947304SEvan Yan 	 * if the corresponding register is zero.  If the value
350326947304SEvan Yan 	 * is non-zero then the property exists with the value
350426947304SEvan Yan 	 * of the register.
350526947304SEvan Yan 	 */
350626947304SEvan Yan 	if ((val = pci_config_get16(config_handle,
350726947304SEvan Yan 	    PCI_CONF_SUBVENID)) != 0) {
350826947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
350926947304SEvan Yan 		    "subsystem-vendor-id", val)) != DDI_SUCCESS) {
351026947304SEvan Yan 			return (ret);
351126947304SEvan Yan 		}
351226947304SEvan Yan 	}
351326947304SEvan Yan 	if ((val = pci_config_get16(config_handle,
351426947304SEvan Yan 	    PCI_CONF_SUBSYSID)) != 0) {
351526947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
351626947304SEvan Yan 		    "subsystem-id", val)) != DDI_SUCCESS) {
351726947304SEvan Yan 			return (ret);
351826947304SEvan Yan 		}
351926947304SEvan Yan 	}
352026947304SEvan Yan 	if ((val = pci_config_get16(config_handle,
352126947304SEvan Yan 	    PCI_CONF_CACHE_LINESZ)) != 0) {
352226947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
352326947304SEvan Yan 		    "cache-line-size", val)) != DDI_SUCCESS) {
352426947304SEvan Yan 			return (ret);
352526947304SEvan Yan 		}
352626947304SEvan Yan 	}
352726947304SEvan Yan 
352826947304SEvan Yan 	/*
352926947304SEvan Yan 	 * If the Interrupt Pin register is non-zero then the
353026947304SEvan Yan 	 * interrupts property exists
353126947304SEvan Yan 	 */
353226947304SEvan Yan 	if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
353326947304SEvan Yan 		/*
353426947304SEvan Yan 		 * If interrupt pin is non-zero,
353526947304SEvan Yan 		 * record the interrupt line used
353626947304SEvan Yan 		 */
353726947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
353826947304SEvan Yan 		    "interrupts", byteval)) != DDI_SUCCESS) {
353926947304SEvan Yan 			return (ret);
354026947304SEvan Yan 		}
354126947304SEvan Yan 	}
354226947304SEvan Yan 
354326947304SEvan Yan 	ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr);
354426947304SEvan Yan 
354526947304SEvan Yan 	if (pcie_dev && (ret == DDI_SUCCESS)) {
354626947304SEvan Yan 		val = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
354726947304SEvan Yan 		    PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
354826947304SEvan Yan 		/* if slot implemented, get physical slot number */
354926947304SEvan Yan 		if (val) {
355026947304SEvan Yan 			wordval = (PCI_CAP_GET32(config_handle, NULL,
355126947304SEvan Yan 			    cap_ptr, PCIE_SLOTCAP) >>
355226947304SEvan Yan 			    PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) &
355326947304SEvan Yan 			    PCIE_SLOTCAP_PHY_SLOT_NUM_MASK;
355426947304SEvan Yan 			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE,
355526947304SEvan Yan 			    dip, "physical-slot#", wordval))
355626947304SEvan Yan 			    != DDI_SUCCESS) {
355726947304SEvan Yan 				return (ret);
355826947304SEvan Yan 			}
355926947304SEvan Yan 		}
356026947304SEvan Yan 	}
356126947304SEvan Yan 	return (PCICFG_SUCCESS);
356226947304SEvan Yan }
356326947304SEvan Yan static int
356426947304SEvan Yan pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type,
356526947304SEvan Yan     int pbus, int sbus)
356626947304SEvan Yan {
356726947304SEvan Yan 	int ret;
356826947304SEvan Yan 	char device_type[8];
356926947304SEvan Yan 
357026947304SEvan Yan 	if (pcie_device_type)
357126947304SEvan Yan 		(void) strcpy(device_type, "pciex");
357226947304SEvan Yan 	else
357326947304SEvan Yan 		(void) strcpy(device_type, "pci");
357426947304SEvan Yan 
357526947304SEvan Yan 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
357626947304SEvan Yan 	    "device_type", device_type)) != DDI_SUCCESS) {
357726947304SEvan Yan 		return (ret);
357826947304SEvan Yan 	}
357926947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
358026947304SEvan Yan 	    "#address-cells", 3)) != DDI_SUCCESS) {
358126947304SEvan Yan 		return (ret);
358226947304SEvan Yan 	}
358326947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
358426947304SEvan Yan 	    "#size-cells", 2)) != DDI_SUCCESS) {
358526947304SEvan Yan 		return (ret);
358626947304SEvan Yan 	}
358726947304SEvan Yan 
358826947304SEvan Yan 	/*
358926947304SEvan Yan 	 * Create primary-bus and secondary-bus properties to be used
359026947304SEvan Yan 	 * to restore bus numbers in the pcicfg_setup_bridge() routine.
359126947304SEvan Yan 	 */
359226947304SEvan Yan 	if (pbus != -1 && sbus != -1) {
359326947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
359426947304SEvan Yan 		    "primary-bus", pbus)) != DDI_SUCCESS) {
359526947304SEvan Yan 				return (ret);
359626947304SEvan Yan 		}
359726947304SEvan Yan 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
359826947304SEvan Yan 		    "secondary-bus", sbus)) != DDI_SUCCESS) {
359926947304SEvan Yan 				return (ret);
360026947304SEvan Yan 		}
360126947304SEvan Yan 	}
360226947304SEvan Yan 	return (PCICFG_SUCCESS);
360326947304SEvan Yan }
360426947304SEvan Yan 
360526947304SEvan Yan static int
360626947304SEvan Yan pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
360726947304SEvan Yan 	uint8_t pcie_dev)
360826947304SEvan Yan {
360926947304SEvan Yan 
361026947304SEvan Yan 	int		ret;
361126947304SEvan Yan 	char		*name;
361226947304SEvan Yan 	char		buffer[64], pprefix[8];
361326947304SEvan Yan 	uint16_t	classcode;
361426947304SEvan Yan 	uint8_t		revid, pif, pclass, psubclass;
361526947304SEvan Yan 	char		*compat[24];
361626947304SEvan Yan 	int		i;
361726947304SEvan Yan 	int		n;
361826947304SEvan Yan 	uint16_t		sub_vid, sub_sid, vid, did;
361926947304SEvan Yan 
362026947304SEvan Yan 	/* set the property prefix based on the device type */
362126947304SEvan Yan 	if (pcie_dev)
362226947304SEvan Yan 		(void) sprintf(pprefix, "pciex");
362326947304SEvan Yan 	else
362426947304SEvan Yan 		(void) sprintf(pprefix, "pci");
362526947304SEvan Yan 	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
362626947304SEvan Yan 	sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
362726947304SEvan Yan 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
362826947304SEvan Yan 	did = pci_config_get16(config_handle, PCI_CONF_DEVID);
362926947304SEvan Yan 	revid = pci_config_get8(config_handle, PCI_CONF_REVID);
363026947304SEvan Yan 	pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
363126947304SEvan Yan 	classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
363226947304SEvan Yan 	pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
363326947304SEvan Yan 	psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
363426947304SEvan Yan 
363526947304SEvan Yan 	/*
363626947304SEvan Yan 	 * NOTE: These are for both a child and PCI-PCI bridge node
363726947304SEvan Yan 	 */
363826947304SEvan Yan 
363926947304SEvan Yan 	/*
364026947304SEvan Yan 	 *	"name" property rule
364126947304SEvan Yan 	 *	--------------------
364226947304SEvan Yan 	 *
364326947304SEvan Yan 	 *
364426947304SEvan Yan 	 * |	  \svid |
364526947304SEvan Yan 	 * |	   \    |
364626947304SEvan Yan 	 * |	    \   |
364726947304SEvan Yan 	 * |	ssid \  |	=0		|	!= 0		|
364826947304SEvan Yan 	 * |------------|-----------------------|-----------------------|
364926947304SEvan Yan 	 * |		|			|			|
365026947304SEvan Yan 	 * |	=0	|	vid,did		|	svid,ssid	|
365126947304SEvan Yan 	 * |		|			|			|
365226947304SEvan Yan 	 * |------------|-----------------------|-----------------------|
365326947304SEvan Yan 	 * |		|			|			|
365426947304SEvan Yan 	 * |	!=0	|	svid,ssid	|	svid,ssid	|
365526947304SEvan Yan 	 * |		|			|			|
365626947304SEvan Yan 	 * |------------|-----------------------|-----------------------|
365726947304SEvan Yan 	 *
365826947304SEvan Yan 	 * where:
365926947304SEvan Yan 	 *    vid = vendor id
366026947304SEvan Yan 	 *    did = device id
366126947304SEvan Yan 	 *   svid = subsystem vendor id
366226947304SEvan Yan 	 *   ssid = subsystem id
366326947304SEvan Yan 	 */
366426947304SEvan Yan 
366526947304SEvan Yan 	if ((sub_sid != 0) || (sub_vid != 0)) {
366626947304SEvan Yan 		(void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid);
366726947304SEvan Yan 	} else {
366826947304SEvan Yan 		(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
366926947304SEvan Yan 	}
367026947304SEvan Yan 
367126947304SEvan Yan 	/*
367226947304SEvan Yan 	 * In some environments, trying to use "generic" 1275 names is
367326947304SEvan Yan 	 * not the convention.  In those cases use the name as created
367426947304SEvan Yan 	 * above.  In all the rest of the cases, check to see if there
367526947304SEvan Yan 	 * is a generic name first.
367626947304SEvan Yan 	 */
367726947304SEvan Yan #ifdef _DONT_USE_1275_GENERIC_NAMES
367826947304SEvan Yan 	name = buffer;
367926947304SEvan Yan #else
368026947304SEvan Yan 	if ((name = pcicfg_get_class_name(classcode)) == NULL) {
368126947304SEvan Yan 		/*
368226947304SEvan Yan 		 * Set name to the above fabricated name
368326947304SEvan Yan 		 */
368426947304SEvan Yan 		name = buffer;
368526947304SEvan Yan 	}
368626947304SEvan Yan #endif
368726947304SEvan Yan 
368826947304SEvan Yan 	/*
368926947304SEvan Yan 	 * The node name field needs to be filled in with the name
369026947304SEvan Yan 	 */
369126947304SEvan Yan 	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
369226947304SEvan Yan 		DEBUG0("Failed to set nodename for node\n");
369326947304SEvan Yan 		return (PCICFG_FAILURE);
369426947304SEvan Yan 	}
369526947304SEvan Yan 
369626947304SEvan Yan 	/*
369726947304SEvan Yan 	 * Create the compatible property as an array of pointers
369826947304SEvan Yan 	 * to strings.  Start with the buffer created above.
369926947304SEvan Yan 	 */
370026947304SEvan Yan 	n = 0;
370126947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
370226947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
370326947304SEvan Yan 
370426947304SEvan Yan 	/*
370526947304SEvan Yan 	 * Setup 'compatible' as per the PCI2.1 bindings document.
370626947304SEvan Yan 	 *	pci[ex]VVVV,DDDD.SSSS.ssss.RR
370726947304SEvan Yan 	 *	pci[ex]VVVV,DDDD.SSSS.ssss
370826947304SEvan Yan 	 *	pciSSSS.ssss  -> not created for PCIe as per PCIe bindings
370926947304SEvan Yan 	 *	pci[ex]VVVV,DDDD.RR
371026947304SEvan Yan 	 *	pci[ex]VVVV,DDDD
371126947304SEvan Yan 	 *	pci[ex]class,CCSSPP
371226947304SEvan Yan 	 *	pci[ex]class,CCSS
371326947304SEvan Yan 	 */
371426947304SEvan Yan 
371526947304SEvan Yan 	/* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
371626947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix,  vid, did,
371726947304SEvan Yan 	    sub_vid, sub_sid, revid);
371826947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
371926947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
372026947304SEvan Yan 
372126947304SEvan Yan 	/* pci[ex]VVVV,DDDD.SSSS.ssss */
372226947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid, did,
372326947304SEvan Yan 	    sub_vid, sub_sid);
372426947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
372526947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
372626947304SEvan Yan 
372726947304SEvan Yan 	/* pciSSSS.ssss  -> not created for PCIe as per PCIe bindings */
372826947304SEvan Yan 	if (!pcie_dev) {
372926947304SEvan Yan 		(void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
373026947304SEvan Yan 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
373126947304SEvan Yan 		(void) strcpy(compat[n++], buffer);
373226947304SEvan Yan 	}
373326947304SEvan Yan 
373426947304SEvan Yan 	/* pci[ex]VVVV,DDDD.RR */
373526947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x.%x", pprefix,  vid, did, revid);
373626947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
373726947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
373826947304SEvan Yan 
373926947304SEvan Yan 	/* pci[ex]VVVV,DDDD */
374026947304SEvan Yan 	(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
374126947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
374226947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
374326947304SEvan Yan 
374426947304SEvan Yan 	/* pci[ex]class,CCSSPP */
374526947304SEvan Yan 	(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
374626947304SEvan Yan 	    pclass, psubclass, pif);
374726947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
374826947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
374926947304SEvan Yan 
375026947304SEvan Yan 	/* pci[ex]class,CCSS */
375126947304SEvan Yan 	(void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
375226947304SEvan Yan 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
375326947304SEvan Yan 	(void) strcpy(compat[n++], buffer);
375426947304SEvan Yan 
375526947304SEvan Yan 	if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
375626947304SEvan Yan 	    "compatible", (char **)compat, n)) != DDI_SUCCESS) {
375726947304SEvan Yan 		return (ret);
375826947304SEvan Yan 	}
375926947304SEvan Yan 
376026947304SEvan Yan 	for (i = 0; i < n; i++) {
376126947304SEvan Yan 		kmem_free(compat[i], strlen(compat[i]) + 1);
376226947304SEvan Yan 	}
376326947304SEvan Yan 
376426947304SEvan Yan 	DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name);
376526947304SEvan Yan 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
376626947304SEvan Yan 	    "name", name)) != DDI_SUCCESS) {
376726947304SEvan Yan 
376826947304SEvan Yan 		DEBUG0("pcicfg_set_childnode_props - Unable to create name "
376926947304SEvan Yan 		    "property\n");
377026947304SEvan Yan 
377126947304SEvan Yan 		return (ret);
377226947304SEvan Yan 	}
377326947304SEvan Yan 
377426947304SEvan Yan 	return (PCICFG_SUCCESS);
377526947304SEvan Yan }
377626947304SEvan Yan 
377726947304SEvan Yan /*
377826947304SEvan Yan  * Program the bus numbers into the bridge
377926947304SEvan Yan  */
378026947304SEvan Yan 
378126947304SEvan Yan static void
378226947304SEvan Yan pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
378326947304SEvan Yan uint_t primary, uint_t secondary, uint_t subordinate)
378426947304SEvan Yan {
378526947304SEvan Yan 	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
378626947304SEvan Yan 	    subordinate);
378726947304SEvan Yan 	/*
378826947304SEvan Yan 	 * Primary bus#
378926947304SEvan Yan 	 */
379026947304SEvan Yan 	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
379126947304SEvan Yan 
379226947304SEvan Yan 	/*
379326947304SEvan Yan 	 * Secondary bus#
379426947304SEvan Yan 	 */
379526947304SEvan Yan 	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
379626947304SEvan Yan 
379726947304SEvan Yan 	/*
379826947304SEvan Yan 	 * Subordinate bus#
379926947304SEvan Yan 	 */
380026947304SEvan Yan 	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
380126947304SEvan Yan }
380226947304SEvan Yan 
380326947304SEvan Yan /*
380426947304SEvan Yan  * Put bridge registers into initial state
380526947304SEvan Yan  */
380626947304SEvan Yan static void
380726947304SEvan Yan pcicfg_setup_bridge(pcicfg_phdl_t *entry,
380826947304SEvan Yan     ddi_acc_handle_t handle, dev_info_t *dip)
380926947304SEvan Yan {
381026947304SEvan Yan 	int pbus, sbus;
381126947304SEvan Yan 
381226947304SEvan Yan 	/*
381326947304SEvan Yan 	 * The highest bus seen during probing is the max-subordinate bus
381426947304SEvan Yan 	 */
381526947304SEvan Yan 	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
381626947304SEvan Yan 
381726947304SEvan Yan 
381826947304SEvan Yan 	/*
381926947304SEvan Yan 	 * If there exists more than 1 downstream bridge, it
382026947304SEvan Yan 	 * will be reset by the below secondary bus reset which
382126947304SEvan Yan 	 * will clear the bus numbers assumed to be programmed in
382226947304SEvan Yan 	 * the pcicfg_probe_children() routine.  We therefore restore
382326947304SEvan Yan 	 * them here.
382426947304SEvan Yan 	 */
382526947304SEvan Yan 	if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) {
382626947304SEvan Yan 		pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
382726947304SEvan Yan 		    DDI_PROP_DONTPASS, "primary-bus", -1);
382826947304SEvan Yan 		sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
382926947304SEvan Yan 		    DDI_PROP_DONTPASS, "secondary-bus", -1);
383026947304SEvan Yan 		if (pbus != -1 && sbus != -1) {
383126947304SEvan Yan 			pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus);
383226947304SEvan Yan 			pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus);
383326947304SEvan Yan 		} else {
383426947304SEvan Yan 			cmn_err(CE_WARN, "Invalid Bridge number detected: \
383526947304SEvan Yan 			    %s%d: pbus = 0x%x, sbus = 0x%x",
383626947304SEvan Yan 			    ddi_get_name(dip), ddi_get_instance(dip), pbus,
383726947304SEvan Yan 			    sbus);
383826947304SEvan Yan 		}
383926947304SEvan Yan 	}
384026947304SEvan Yan 
384126947304SEvan Yan 	/*
384226947304SEvan Yan 	 * Reset the secondary bus
384326947304SEvan Yan 	 */
384426947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
384526947304SEvan Yan 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
384626947304SEvan Yan 
384726947304SEvan Yan 	drv_usecwait(100);
384826947304SEvan Yan 
384926947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
385026947304SEvan Yan 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
385126947304SEvan Yan 
385226947304SEvan Yan 	/*
385326947304SEvan Yan 	 * Program the memory base register with the
385426947304SEvan Yan 	 * start of the memory range
385526947304SEvan Yan 	 */
385626947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
385726947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
385826947304SEvan Yan 
385926947304SEvan Yan 	/*
386026947304SEvan Yan 	 * Program the I/O base register with the start of the I/O range
386126947304SEvan Yan 	 */
386226947304SEvan Yan 	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
386326947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
386426947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
386526947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
386626947304SEvan Yan 
386726947304SEvan Yan 	/*
386826947304SEvan Yan 	 * Clear status bits
386926947304SEvan Yan 	 */
387026947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
387126947304SEvan Yan 
387226947304SEvan Yan 	/*
387326947304SEvan Yan 	 * Turn off prefetchable range
387426947304SEvan Yan 	 */
387526947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
387626947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
387726947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
387826947304SEvan Yan 
387926947304SEvan Yan 	/*
388026947304SEvan Yan 	 * Needs to be set to this value
388126947304SEvan Yan 	 */
388226947304SEvan Yan 	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
388326947304SEvan Yan 
388426947304SEvan Yan 	/*
388526947304SEvan Yan 	 * After a Reset, we need to wait 2^25 clock cycles before the
388626947304SEvan Yan 	 * first Configuration access.  The worst case is 33MHz, which
388726947304SEvan Yan 	 * is a 1 second wait.
388826947304SEvan Yan 	 */
388926947304SEvan Yan 	drv_usecwait(pcicfg_sec_reset_delay);
389026947304SEvan Yan 
389126947304SEvan Yan }
389226947304SEvan Yan 
389326947304SEvan Yan static void
389426947304SEvan Yan pcicfg_update_bridge(pcicfg_phdl_t *entry,
389526947304SEvan Yan 	ddi_acc_handle_t handle)
389626947304SEvan Yan {
389726947304SEvan Yan 	uint_t length;
389826947304SEvan Yan 
389926947304SEvan Yan 	/*
390026947304SEvan Yan 	 * Program the memory limit register with the end of the memory range
390126947304SEvan Yan 	 */
390226947304SEvan Yan 
390326947304SEvan Yan 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
390426947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last,
390526947304SEvan Yan 	    PCICFG_MEMGRAN));
390626947304SEvan Yan 
390726947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
390826947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(
390926947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last,
391026947304SEvan Yan 	    PCICFG_MEMGRAN))));
391126947304SEvan Yan 	/*
391226947304SEvan Yan 	 * Since this is a bridge, the rest of this range will
391326947304SEvan Yan 	 * be responded to by the bridge.  We have to round up
391426947304SEvan Yan 	 * so no other device claims it.
391526947304SEvan Yan 	 */
391626947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->memory_last,
391726947304SEvan Yan 	    PCICFG_MEMGRAN) - entry->memory_last)) > 0) {
391826947304SEvan Yan 		(void) pcicfg_get_mem(entry, length, NULL);
391926947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of "
392026947304SEvan Yan 		    "the bridge (mem)\n", length);
392126947304SEvan Yan 	}
392226947304SEvan Yan 
392326947304SEvan Yan 	/*
392426947304SEvan Yan 	 * Program the I/O limit register with the end of the I/O range
392526947304SEvan Yan 	 */
392626947304SEvan Yan 	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
392726947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(
392826947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
392926947304SEvan Yan 	    PCICFG_IOGRAN)))));
393026947304SEvan Yan 
393126947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
393226947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
393326947304SEvan Yan 	    PCICFG_IOGRAN))));
393426947304SEvan Yan 
393526947304SEvan Yan 	/*
393626947304SEvan Yan 	 * Same as above for I/O space. Since this is a
393726947304SEvan Yan 	 * bridge, the rest of this range will be responded
393826947304SEvan Yan 	 * to by the bridge.  We have to round up so no
393926947304SEvan Yan 	 * other device claims it.
394026947304SEvan Yan 	 */
394126947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->io_last,
394226947304SEvan Yan 	    PCICFG_IOGRAN) - entry->io_last)) > 0) {
394326947304SEvan Yan 		(void) pcicfg_get_io(entry, length, NULL);
394426947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of "
394526947304SEvan Yan 		    "the bridge (I/O)\n",  length);
394626947304SEvan Yan 	}
394726947304SEvan Yan }
394826947304SEvan Yan 
394926947304SEvan Yan /*ARGSUSED*/
395026947304SEvan Yan static void
395126947304SEvan Yan pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
395226947304SEvan Yan 	pcicfg_err_regs_t *regs)
395326947304SEvan Yan {
395426947304SEvan Yan 	uint16_t val;
395526947304SEvan Yan 
395626947304SEvan Yan 	/* disable SERR generated in the context of Master Aborts. */
395726947304SEvan Yan 	regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM);
395826947304SEvan Yan 	val &= ~PCI_COMM_SERR_ENABLE;
395926947304SEvan Yan 	pci_config_put16(h, PCI_CONF_COMM, val);
396026947304SEvan Yan 	regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL);
396126947304SEvan Yan 	val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
396226947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL, val);
396326947304SEvan Yan 	/* clear any current pending errors */
396426947304SEvan Yan 	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
396526947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
396626947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
396726947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
396826947304SEvan Yan 	/* if we are a PCIe device, disable the generation of UR, CE and NFE */
396926947304SEvan Yan 	if (regs->pcie_dev) {
397026947304SEvan Yan 		uint16_t devctl;
397126947304SEvan Yan 		uint16_t cap_ptr;
397226947304SEvan Yan 
397326947304SEvan Yan 		if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
397426947304SEvan Yan 		    DDI_FAILURE)
397526947304SEvan Yan 			return;
397626947304SEvan Yan 
397726947304SEvan Yan 		regs->pcie_cap_off = cap_ptr;
397826947304SEvan Yan 		regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr,
397926947304SEvan Yan 		    PCIE_DEVCTL);
398026947304SEvan Yan 		devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN |
398126947304SEvan Yan 		    PCIE_DEVCTL_CE_REPORTING_EN |
398226947304SEvan Yan 		    PCIE_DEVCTL_NFE_REPORTING_EN |
398326947304SEvan Yan 		    PCIE_DEVCTL_FE_REPORTING_EN);
398426947304SEvan Yan 		PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl);
398526947304SEvan Yan 	}
398626947304SEvan Yan }
398726947304SEvan Yan 
398826947304SEvan Yan /*ARGSUSED*/
398926947304SEvan Yan static void
399026947304SEvan Yan pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
399126947304SEvan Yan 	pcicfg_err_regs_t *regs)
399226947304SEvan Yan {
399326947304SEvan Yan 	/* clear any pending errors */
399426947304SEvan Yan 	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
399526947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
399626947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
399726947304SEvan Yan 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
399826947304SEvan Yan 
399926947304SEvan Yan 	/* restore original settings */
400026947304SEvan Yan 	if (regs->pcie_dev) {
400126947304SEvan Yan 		pcie_clear_errors(dip);
400226947304SEvan Yan 		pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
400326947304SEvan Yan 		    regs->devctl);
400426947304SEvan Yan 	}
400526947304SEvan Yan 
400626947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl);
400726947304SEvan Yan 	pci_config_put16(h, PCI_CONF_COMM, regs->cmd);
400826947304SEvan Yan 
400926947304SEvan Yan }
401026947304SEvan Yan 
401126947304SEvan Yan static int
401226947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
4013c0da6274SZhi-Jun Robin Fu     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
401426947304SEvan Yan {
401526947304SEvan Yan 	dev_info_t		*new_child;
401626947304SEvan Yan 	ddi_acc_handle_t	config_handle;
401726947304SEvan Yan 	uint8_t			header_type, pcie_dev = 0;
401826947304SEvan Yan 	int			ret;
401926947304SEvan Yan 	pcicfg_err_regs_t	regs;
402026947304SEvan Yan 
402126947304SEvan Yan 	/*
402226947304SEvan Yan 	 * This node will be put immediately below
402326947304SEvan Yan 	 * "parent". Allocate a blank device node.  It will either
402426947304SEvan Yan 	 * be filled in or freed up based on further probing.
402526947304SEvan Yan 	 */
402626947304SEvan Yan 	/*
402726947304SEvan Yan 	 * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c
402826947304SEvan Yan 	 * ndi_devi_alloc() is called as ndi_devi_alloc_sleep()
402926947304SEvan Yan 	 */
403026947304SEvan Yan 	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
403126947304SEvan Yan 	    (pnode_t)DEVI_SID_NODEID, &new_child)
403226947304SEvan Yan 	    != NDI_SUCCESS) {
403326947304SEvan Yan 		DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n");
403426947304SEvan Yan 		return (PCICFG_FAILURE);
403526947304SEvan Yan 	}
403626947304SEvan Yan 
403726947304SEvan Yan 	if (pcicfg_add_config_reg(new_child, bus,
403826947304SEvan Yan 	    device, func) != DDI_SUCCESS) {
403926947304SEvan Yan 		DEBUG0("pcicfg_probe_children():"
404026947304SEvan Yan 		    "Failed to add candidate REG\n");
404126947304SEvan Yan 		goto failedconfig;
404226947304SEvan Yan 	}
404326947304SEvan Yan 
404426947304SEvan Yan 	if ((ret = pcicfg_config_setup(new_child, &config_handle))
404526947304SEvan Yan 	    != PCICFG_SUCCESS) {
404626947304SEvan Yan 		if (ret == PCICFG_NODEVICE) {
404726947304SEvan Yan 			(void) ndi_devi_free(new_child);
404826947304SEvan Yan 			return (ret);
404926947304SEvan Yan 		}
405026947304SEvan Yan 		DEBUG0("pcicfg_probe_children():"
405126947304SEvan Yan 		    "Failed to setup config space\n");
405226947304SEvan Yan 		goto failedconfig;
405326947304SEvan Yan 	}
405426947304SEvan Yan 
4055c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4056c0da6274SZhi-Jun Robin Fu 		(void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
4057c0da6274SZhi-Jun Robin Fu 		    PCIE_BUS_INITIAL);
4058c0da6274SZhi-Jun Robin Fu 
405926947304SEvan Yan 	/*
406026947304SEvan Yan 	 * As soon as we have access to config space,
406126947304SEvan Yan 	 * turn off device. It will get turned on
406226947304SEvan Yan 	 * later (after memory is assigned).
406326947304SEvan Yan 	 */
406426947304SEvan Yan 	(void) pcicfg_device_off(config_handle);
406526947304SEvan Yan 
406626947304SEvan Yan 	/* check if we are PCIe device */
406726947304SEvan Yan 	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
406826947304SEvan Yan 	    == DDI_SUCCESS) {
406926947304SEvan Yan 		DEBUG0("PCIe device detected\n");
407026947304SEvan Yan 		pcie_dev = 1;
407126947304SEvan Yan 	}
407226947304SEvan Yan 
407326947304SEvan Yan 	/*
407426947304SEvan Yan 	 * Set 1275 properties common to all devices
407526947304SEvan Yan 	 */
407626947304SEvan Yan 	if (pcicfg_set_standard_props(new_child, config_handle,
407726947304SEvan Yan 	    pcie_dev) != PCICFG_SUCCESS) {
407826947304SEvan Yan 		DEBUG0("Failed to set standard properties\n");
407926947304SEvan Yan 		goto failedchild;
408026947304SEvan Yan 	}
408126947304SEvan Yan 
408226947304SEvan Yan 	/*
408326947304SEvan Yan 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
408426947304SEvan Yan 	 */
408526947304SEvan Yan 	if (pcicfg_set_childnode_props(new_child, config_handle,
408626947304SEvan Yan 	    pcie_dev) != PCICFG_SUCCESS) {
408726947304SEvan Yan 		goto failedchild;
408826947304SEvan Yan 	}
408926947304SEvan Yan 
409026947304SEvan Yan 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
409126947304SEvan Yan 
409226947304SEvan Yan 	/*
409326947304SEvan Yan 	 * If this is not a multi-function card only probe function zero.
409426947304SEvan Yan 	 */
409526947304SEvan Yan 	if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
409626947304SEvan Yan 
409726947304SEvan Yan 		(void) pcicfg_config_teardown(&config_handle);
409826947304SEvan Yan 		(void) ndi_devi_free(new_child);
409926947304SEvan Yan 		return (PCICFG_NODEVICE);
410026947304SEvan Yan 	}
410126947304SEvan Yan 
410226947304SEvan Yan 	DEBUG1("---Vendor ID = [0x%x]\n",
410326947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID));
410426947304SEvan Yan 	DEBUG1("---Device ID = [0x%x]\n",
410526947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
410626947304SEvan Yan 
410726947304SEvan Yan 	/*
410826947304SEvan Yan 	 * Attach the child to its parent
410926947304SEvan Yan 	 */
411026947304SEvan Yan 	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
411126947304SEvan Yan 
411226947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
411326947304SEvan Yan 
411426947304SEvan Yan 		DEBUG3("--Bridge found bus [0x%x] device"
411526947304SEvan Yan 		    "[0x%x] func [0x%x]\n", bus, device, func);
411626947304SEvan Yan 
411726947304SEvan Yan 		/* Only support read-only probe for leaf device */
411826947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
411926947304SEvan Yan 			goto failedchild;
412026947304SEvan Yan 
412126947304SEvan Yan 		if (pcicfg_probe_bridge(new_child, config_handle,
4122c0da6274SZhi-Jun Robin Fu 		    bus, highest_bus, is_pcie) != PCICFG_SUCCESS) {
412326947304SEvan Yan 			(void) pcicfg_free_bridge_resources(new_child);
412426947304SEvan Yan 			goto failedchild;
412526947304SEvan Yan 		}
412626947304SEvan Yan 
412726947304SEvan Yan 	} else {
412826947304SEvan Yan 
412926947304SEvan Yan 		DEBUG3("--Leaf device found bus [0x%x] device"
413026947304SEvan Yan 		    "[0x%x] func [0x%x]\n",
413126947304SEvan Yan 		    bus, device, func);
413226947304SEvan Yan 
413326947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY) {
413426947304SEvan Yan 			/*
413526947304SEvan Yan 			 * with read-only probe, don't do any resource
413626947304SEvan Yan 			 * allocation, just read the BARs and update props.
413726947304SEvan Yan 			 */
413826947304SEvan Yan 			ret = pcicfg_populate_props_from_bar(new_child,
413926947304SEvan Yan 			    config_handle);
414026947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
414126947304SEvan Yan 				goto failedchild;
414226947304SEvan Yan 
414326947304SEvan Yan 			/*
414426947304SEvan Yan 			 * for readonly probe "assigned-addresses" property
414526947304SEvan Yan 			 * has already been setup by reading the BAR, here
414626947304SEvan Yan 			 * just substract the resource from its parent here.
414726947304SEvan Yan 			 */
414826947304SEvan Yan 			ret = pcicfg_device_assign_readonly(new_child);
414926947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
415026947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child,
415126947304SEvan Yan 				    flags);
415226947304SEvan Yan 				goto failedchild;
415326947304SEvan Yan 			}
415426947304SEvan Yan 		} else {
415526947304SEvan Yan 			/*
415626947304SEvan Yan 			 * update "reg" property by sizing the BARs.
415726947304SEvan Yan 			 */
415826947304SEvan Yan 			ret = pcicfg_populate_reg_props(new_child,
415926947304SEvan Yan 			    config_handle);
416026947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
416126947304SEvan Yan 				goto failedchild;
416226947304SEvan Yan 
416326947304SEvan Yan 			/* now allocate & program the resources */
416426947304SEvan Yan 			ret = pcicfg_device_assign(new_child);
416526947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
416626947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child,
416726947304SEvan Yan 				    flags);
416826947304SEvan Yan 				goto failedchild;
416926947304SEvan Yan 			}
417026947304SEvan Yan 		}
417126947304SEvan Yan 
417226947304SEvan Yan 		(void) ndi_devi_bind_driver(new_child, 0);
417326947304SEvan Yan 	}
417426947304SEvan Yan 
417526947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
4176c0da6274SZhi-Jun Robin Fu 
4177c0da6274SZhi-Jun Robin Fu 	/*
4178c0da6274SZhi-Jun Robin Fu 	 * Properties have been setted up, so initilize the rest fields
4179c0da6274SZhi-Jun Robin Fu 	 * in bus_t.
4180c0da6274SZhi-Jun Robin Fu 	 */
4181c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4182c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
4183c0da6274SZhi-Jun Robin Fu 
418426947304SEvan Yan 	return (PCICFG_SUCCESS);
418526947304SEvan Yan 
418626947304SEvan Yan failedchild:
418726947304SEvan Yan 
418826947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
4189c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4190c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_FINAL);
419126947304SEvan Yan 
419226947304SEvan Yan failedconfig:
419326947304SEvan Yan 
419426947304SEvan Yan 	(void) ndi_devi_free(new_child);
419526947304SEvan Yan 	return (PCICFG_FAILURE);
419626947304SEvan Yan }
419726947304SEvan Yan 
419826947304SEvan Yan /*
419926947304SEvan Yan  * Sizing the BARs and update "reg" property
420026947304SEvan Yan  */
420126947304SEvan Yan static int
420226947304SEvan Yan pcicfg_populate_reg_props(dev_info_t *new_child,
420326947304SEvan Yan     ddi_acc_handle_t config_handle)
420426947304SEvan Yan {
420526947304SEvan Yan 	int		i;
420626947304SEvan Yan 	uint32_t	request;
420726947304SEvan Yan 
420826947304SEvan Yan 	i = PCI_CONF_BASE0;
420926947304SEvan Yan 
421026947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
421126947304SEvan Yan 
421226947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
421326947304SEvan Yan 
421426947304SEvan Yan 		request = pci_config_get32(config_handle, i);
421526947304SEvan Yan 		/*
421626947304SEvan Yan 		 * If its a zero length, don't do
421726947304SEvan Yan 		 * any programming.
421826947304SEvan Yan 		 */
421926947304SEvan Yan 		if (request != 0) {
422026947304SEvan Yan 			/*
422126947304SEvan Yan 			 * Add to the "reg" property
422226947304SEvan Yan 			 */
422326947304SEvan Yan 			if (pcicfg_update_reg_prop(new_child,
422426947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
422526947304SEvan Yan 				goto failedchild;
422626947304SEvan Yan 			}
422726947304SEvan Yan 		} else {
422826947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for "
422926947304SEvan Yan 			    "[0x0]=[0x0](32)\n", i);
423026947304SEvan Yan 			i += 4;
423126947304SEvan Yan 			continue;
423226947304SEvan Yan 		}
423326947304SEvan Yan 
423426947304SEvan Yan 		/*
423526947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
423626947304SEvan Yan 		 */
423726947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
423826947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
423926947304SEvan Yan 			    "[0x%x]=[0x%x] (64)\n",
424026947304SEvan Yan 			    i, request,
424126947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
424226947304SEvan Yan 			i += 8;
424326947304SEvan Yan 		} else {
424426947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
424526947304SEvan Yan 			    "[0x%x]=[0x%x](32)\n",
424626947304SEvan Yan 			    i, request,
424726947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
424826947304SEvan Yan 			i += 4;
424926947304SEvan Yan 		}
425026947304SEvan Yan 	}
425126947304SEvan Yan 
425226947304SEvan Yan 	/*
425326947304SEvan Yan 	 * Get the ROM size and create register for it
425426947304SEvan Yan 	 */
425526947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
425626947304SEvan Yan 
425726947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
425826947304SEvan Yan 	/*
425926947304SEvan Yan 	 * If its a zero length, don't do
426026947304SEvan Yan 	 * any programming.
426126947304SEvan Yan 	 */
426226947304SEvan Yan 
426326947304SEvan Yan 	if (request != 0) {
426426947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
426526947304SEvan Yan 		    PCI_CONF_ROM, request,
426626947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
426726947304SEvan Yan 		/*
426826947304SEvan Yan 		 * Add to the "reg" property
426926947304SEvan Yan 		 */
427026947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child,
427126947304SEvan Yan 		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
427226947304SEvan Yan 			goto failedchild;
427326947304SEvan Yan 		}
427426947304SEvan Yan 	}
427526947304SEvan Yan 
427626947304SEvan Yan 	return (PCICFG_SUCCESS);
427726947304SEvan Yan 
427826947304SEvan Yan failedchild:
427926947304SEvan Yan 	return (PCICFG_FAILURE);
428026947304SEvan Yan }
428126947304SEvan Yan 
428226947304SEvan Yan static int
428326947304SEvan Yan pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
4284c0da6274SZhi-Jun Robin Fu     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
428526947304SEvan Yan {
428626947304SEvan Yan 	dev_info_t		*new_child;
428726947304SEvan Yan 	int8_t			header_type;
428826947304SEvan Yan 	int			ret;
428926947304SEvan Yan 	ddi_acc_handle_t	h, ph;
429026947304SEvan Yan 	int			error = 0;
429126947304SEvan Yan 	extern int		pcicfg_dont_interpret;
429226947304SEvan Yan 	pcicfg_err_regs_t	parent_regs, regs;
429326947304SEvan Yan 	char			*status_prop = NULL;
429426947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
429526947304SEvan Yan 	struct pci_ops_bus_args	po;
429626947304SEvan Yan 	fco_handle_t		c;
429726947304SEvan Yan 	char			unit_address[64];
429826947304SEvan Yan 	int			fcode_size = 0;
429926947304SEvan Yan 	uchar_t			*fcode_addr;
430026947304SEvan Yan 	uint64_t		mem_answer, mem_alen;
430126947304SEvan Yan 	pci_regspec_t		p;
430226947304SEvan Yan 	int32_t			request;
430326947304SEvan Yan 	ndi_ra_request_t	req;
430426947304SEvan Yan 	int16_t			vendor_id, device_id;
430526947304SEvan Yan #endif
430626947304SEvan Yan 
430726947304SEvan Yan 	/*
430826947304SEvan Yan 	 * check if our parent is of type pciex.
430926947304SEvan Yan 	 * if so, program config space to disable error msgs during probe.
431026947304SEvan Yan 	 */
431126947304SEvan Yan 	if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs)
431226947304SEvan Yan 	    == DDI_SUCCESS) {
431326947304SEvan Yan 		DEBUG0("PCI/PCIe parent detected. Disable errors.\n");
431426947304SEvan Yan 		/*
431526947304SEvan Yan 		 * disable parent generating URs or SERR#s during probing
431626947304SEvan Yan 		 * alone.
431726947304SEvan Yan 		 */
431826947304SEvan Yan 		if (pci_config_setup(parent, &ph) != DDI_SUCCESS)
431926947304SEvan Yan 			return (DDI_FAILURE);
432026947304SEvan Yan 
432126947304SEvan Yan 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
432226947304SEvan Yan 			pcicfg_disable_bridge_probe_err(parent,
432326947304SEvan Yan 			    ph, &parent_regs);
432426947304SEvan Yan 		}
432526947304SEvan Yan 	}
432626947304SEvan Yan 
432726947304SEvan Yan 	/*
432826947304SEvan Yan 	 * This node will be put immediately below
432926947304SEvan Yan 	 * "parent". Allocate a blank device node.  It will either
433026947304SEvan Yan 	 * be filled in or freed up based on further probing.
433126947304SEvan Yan 	 */
433226947304SEvan Yan 
433326947304SEvan Yan 	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
433426947304SEvan Yan 	    (pnode_t)DEVI_SID_NODEID, &new_child)
433526947304SEvan Yan 	    != NDI_SUCCESS) {
433626947304SEvan Yan 		DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n");
433726947304SEvan Yan 		/* return (PCICFG_FAILURE); */
433826947304SEvan Yan 		ret = PCICFG_FAILURE;
433926947304SEvan Yan 		goto failed2;
434026947304SEvan Yan 	}
434126947304SEvan Yan 
434226947304SEvan Yan 	/*
434326947304SEvan Yan 	 * Create a dummy reg property.  This will be replaced with
434426947304SEvan Yan 	 * a real reg property when fcode completes or if we need to
434526947304SEvan Yan 	 * produce one by hand.
434626947304SEvan Yan 	 */
434726947304SEvan Yan 	if (pcicfg_add_config_reg(new_child, bus,
434826947304SEvan Yan 	    device, func) != DDI_SUCCESS) {
434926947304SEvan Yan 		ret = PCICFG_FAILURE;
435026947304SEvan Yan 		goto failed3;
435126947304SEvan Yan 	}
435226947304SEvan Yan #ifdef	EFCODE21554
435326947304SEvan Yan 	if ((ret = pcicfg_config_setup(new_child, &h))
435426947304SEvan Yan 	    != PCICFG_SUCCESS) {
435526947304SEvan Yan 		DEBUG0("pcicfg_fcode_probe():"
435626947304SEvan Yan 		    "Failed to setup config space\n");
435726947304SEvan Yan 		ret = PCICFG_NODEVICE;
435826947304SEvan Yan 		goto failed3;
435926947304SEvan Yan 	}
436026947304SEvan Yan 
436126947304SEvan Yan #else
436226947304SEvan Yan 	p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
436326947304SEvan Yan 	p.pci_phys_mid = p.pci_phys_low = 0;
436426947304SEvan Yan 	p.pci_size_hi = p.pci_size_low = 0;
436526947304SEvan Yan 
436626947304SEvan Yan 	/*
436726947304SEvan Yan 	 * Map in configuration space (temporarily)
436826947304SEvan Yan 	 */
436926947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
437026947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
437126947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
437226947304SEvan Yan 
437326947304SEvan Yan 	if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) {
437426947304SEvan Yan 		DEBUG0("pcicfg_fcode_probe():"
437526947304SEvan Yan 		    "Failed to setup config space\n");
437626947304SEvan Yan 		ret = PCICFG_NODEVICE;
437726947304SEvan Yan 		goto failed3;
437826947304SEvan Yan 	}
437926947304SEvan Yan 
438026947304SEvan Yan 	/*
438126947304SEvan Yan 	 * First use ddi_peek16 so that if there is not a device there,
438226947304SEvan Yan 	 * a bus error will not cause a panic.
438326947304SEvan Yan 	 */
438426947304SEvan Yan 	v = virt + PCI_CONF_VENID;
438526947304SEvan Yan 	if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) {
438626947304SEvan Yan 		DEBUG0("Can not read Vendor ID");
438726947304SEvan Yan 		pcicfg_unmap_phys(&h, &p);
438826947304SEvan Yan 		ret = PCICFG_NODEVICE;
438926947304SEvan Yan 		goto failed3;
439026947304SEvan Yan 	}
439126947304SEvan Yan #endif
4392c0da6274SZhi-Jun Robin Fu 
4393c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4394c0da6274SZhi-Jun Robin Fu 		(void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
4395c0da6274SZhi-Jun Robin Fu 		    PCIE_BUS_INITIAL);
4396c0da6274SZhi-Jun Robin Fu 
439726947304SEvan Yan 	DEBUG0("fcode_probe: conf space mapped.\n");
439826947304SEvan Yan 	/*
439926947304SEvan Yan 	 * As soon as we have access to config space,
440026947304SEvan Yan 	 * turn off device. It will get turned on
440126947304SEvan Yan 	 * later (after memory is assigned).
440226947304SEvan Yan 	 */
440326947304SEvan Yan 	(void) pcicfg_device_off(h);
440426947304SEvan Yan 
440526947304SEvan Yan 	/* check if we are PCIe device */
440626947304SEvan Yan 	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
440726947304SEvan Yan 	    == DDI_SUCCESS) {
440826947304SEvan Yan 		/*EMPTY*/
440926947304SEvan Yan 		DEBUG0("PCI/PCIe device detected\n");
441026947304SEvan Yan 	}
441126947304SEvan Yan 
441226947304SEvan Yan 	/*
441326947304SEvan Yan 	 * Set 1275 properties common to all devices
441426947304SEvan Yan 	 */
441526947304SEvan Yan 	if (pcicfg_set_standard_props(new_child,
441626947304SEvan Yan 	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
441726947304SEvan Yan 		DEBUG0("Failed to set standard properties\n");
441826947304SEvan Yan 		goto failed;
441926947304SEvan Yan 	}
442026947304SEvan Yan 
442126947304SEvan Yan 	/*
442226947304SEvan Yan 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
442326947304SEvan Yan 	 */
442426947304SEvan Yan 	if (pcicfg_set_childnode_props(new_child,
442526947304SEvan Yan 	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
442626947304SEvan Yan 		ret = PCICFG_FAILURE;
442726947304SEvan Yan 		goto failed;
442826947304SEvan Yan 	}
442926947304SEvan Yan 
443026947304SEvan Yan 	header_type = pci_config_get8(h, PCI_CONF_HEADER);
443126947304SEvan Yan 
443226947304SEvan Yan 	/*
443326947304SEvan Yan 	 * If this is not a multi-function card only probe function zero.
443426947304SEvan Yan 	 */
443526947304SEvan Yan 	if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) {
443626947304SEvan Yan 
443726947304SEvan Yan 		ret = PCICFG_NODEVICE;
443826947304SEvan Yan 		goto failed;
443926947304SEvan Yan 	}
444026947304SEvan Yan 
444126947304SEvan Yan 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
444226947304SEvan Yan 
444326947304SEvan Yan 		/*
444426947304SEvan Yan 		 * XXX - Transparent bridges are handled differently
444526947304SEvan Yan 		 * than other devices with regards to fcode.  Since
444626947304SEvan Yan 		 * no transparent bridge currently ships with fcode,
444726947304SEvan Yan 		 * there is no reason to try to extract it from its rom
444826947304SEvan Yan 		 * or call the fcode interpreter to try to load a drop-in.
444926947304SEvan Yan 		 * If fcode is developed to handle transparent bridges,
445026947304SEvan Yan 		 * this code will have to change.
445126947304SEvan Yan 		 */
445226947304SEvan Yan 
445326947304SEvan Yan 		DEBUG3("--Bridge found bus [0x%x] device"
445426947304SEvan Yan 		    "[0x%x] func [0x%x]\n", bus, device, func);
445526947304SEvan Yan 
445626947304SEvan Yan 		/* Only support read-only probe for leaf device */
445726947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
445826947304SEvan Yan 			goto failed;
445926947304SEvan Yan 
446026947304SEvan Yan 		if ((ret = pcicfg_probe_bridge(new_child, h,
4461c0da6274SZhi-Jun Robin Fu 		    bus, highest_bus, is_pcie)) != PCICFG_SUCCESS)
446226947304SEvan Yan 			(void) pcicfg_free_bridge_resources(new_child);
446326947304SEvan Yan 		goto done;
446426947304SEvan Yan 	} else {
446526947304SEvan Yan 
446626947304SEvan Yan 		DEBUG3("--Leaf device found bus [0x%x] device"
446726947304SEvan Yan 		    "[0x%x] func [0x%x]\n",
446826947304SEvan Yan 		    bus, device, func);
446926947304SEvan Yan 
447026947304SEvan Yan 		/*
447126947304SEvan Yan 		 * link in tree, but don't bind driver
447226947304SEvan Yan 		 * We don't have compatible property yet
447326947304SEvan Yan 		 */
447426947304SEvan Yan 		(void) i_ndi_config_node(new_child, DS_LINKED, 0);
447526947304SEvan Yan 
447626947304SEvan Yan 		/* XXX for now, don't run Fcode in read-only probe. */
447726947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
447826947304SEvan Yan 			goto no_fcode;
447926947304SEvan Yan 
448026947304SEvan Yan 		if (pci_config_get8(h, PCI_CONF_IPIN)) {
448126947304SEvan Yan 			pci_config_put8(h, PCI_CONF_ILINE, 0xf);
448226947304SEvan Yan 		}
448326947304SEvan Yan 
448426947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
448526947304SEvan Yan 		/*
448626947304SEvan Yan 		 * Some platforms (x86) don't run fcode, so don't interpret
448726947304SEvan Yan 		 * fcode that might be in the ROM.
448826947304SEvan Yan 		 */
448926947304SEvan Yan 		if (pcicfg_dont_interpret == 0) {
449026947304SEvan Yan 
449126947304SEvan Yan 			/* This platform supports fcode */
449226947304SEvan Yan 
449326947304SEvan Yan 			vendor_id = pci_config_get16(h, PCI_CONF_VENID);
449426947304SEvan Yan 			device_id = pci_config_get16(h, PCI_CONF_DEVID);
449526947304SEvan Yan 
449626947304SEvan Yan 			/*
449726947304SEvan Yan 			 * Get the ROM size and create register for it
449826947304SEvan Yan 			 */
449926947304SEvan Yan 			pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe);
450026947304SEvan Yan 
450126947304SEvan Yan 			request = pci_config_get32(h, PCI_CONF_ROM);
450226947304SEvan Yan 
450326947304SEvan Yan 			/*
450426947304SEvan Yan 			 * If its a zero length, don't do
450526947304SEvan Yan 			 * any programming.
450626947304SEvan Yan 			 */
450726947304SEvan Yan 
450826947304SEvan Yan 			if (request != 0) {
450926947304SEvan Yan 				/*
451026947304SEvan Yan 				 * Add resource to assigned-addresses.
451126947304SEvan Yan 				 */
451226947304SEvan Yan 				if (pcicfg_fcode_assign_bars(h, new_child,
451326947304SEvan Yan 				    bus, device, func, request, &p)
451426947304SEvan Yan 				    != PCICFG_SUCCESS) {
451526947304SEvan Yan 					DEBUG0("Failed to assign addresses to "
451626947304SEvan Yan 					    "implemented BARs");
451726947304SEvan Yan 					ret = PCICFG_FAILURE;
451826947304SEvan Yan 					goto failed;
451926947304SEvan Yan 				}
452026947304SEvan Yan 
452126947304SEvan Yan 				/* Turn device on */
452226947304SEvan Yan 				(void) pcicfg_device_on(h);
452326947304SEvan Yan 
452426947304SEvan Yan 				/*
452526947304SEvan Yan 				 * Attempt to load fcode.
452626947304SEvan Yan 				 */
452726947304SEvan Yan 				(void) pcicfg_load_fcode(new_child, bus, device,
452826947304SEvan Yan 				    func, vendor_id, device_id, &fcode_addr,
452926947304SEvan Yan 				    &fcode_size, PCICFG_LOADDR(mem_answer),
453026947304SEvan Yan 				    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
453126947304SEvan Yan 
453226947304SEvan Yan 				/* Turn device off */
453326947304SEvan Yan 				(void) pcicfg_device_off(h);
453426947304SEvan Yan 
453526947304SEvan Yan 				/*
453626947304SEvan Yan 				 * Free the ROM resources.
453726947304SEvan Yan 				 */
453826947304SEvan Yan 				(void) pcicfg_free_resource(new_child, p, 0);
453926947304SEvan Yan 
454026947304SEvan Yan 				DEBUG2("configure: fcode addr %lx size %x\n",
454126947304SEvan Yan 				    fcode_addr, fcode_size);
454226947304SEvan Yan 
454326947304SEvan Yan 				/*
454426947304SEvan Yan 				 * Create the fcode-rom-offset property.  The
454526947304SEvan Yan 				 * buffer containing the fcode always starts
454626947304SEvan Yan 				 * with 0xF1, so the fcode offset is zero.
454726947304SEvan Yan 				 */
454826947304SEvan Yan 				if (ndi_prop_update_int(DDI_DEV_T_NONE,
454926947304SEvan Yan 				    new_child, "fcode-rom-offset", 0)
455026947304SEvan Yan 				    != DDI_SUCCESS) {
455126947304SEvan Yan 					DEBUG0("Failed to create "
455226947304SEvan Yan 					    "fcode-rom-offset property\n");
455326947304SEvan Yan 					ret = PCICFG_FAILURE;
455426947304SEvan Yan 					goto failed;
455526947304SEvan Yan 				}
455626947304SEvan Yan 			} else {
455726947304SEvan Yan 				DEBUG0("There is no Expansion ROM\n");
455826947304SEvan Yan 				fcode_addr = NULL;
455926947304SEvan Yan 				fcode_size = 0;
456026947304SEvan Yan 			}
456126947304SEvan Yan 
456226947304SEvan Yan 			/*
456326947304SEvan Yan 			 * Fill in the bus specific arguments. For
456426947304SEvan Yan 			 * PCI, it is the config address.
456526947304SEvan Yan 			 */
456626947304SEvan Yan 			po.config_address =
456726947304SEvan Yan 			    PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
456826947304SEvan Yan 
456926947304SEvan Yan 			DEBUG1("config_address=%x\n", po.config_address);
457026947304SEvan Yan 
457126947304SEvan Yan 			/*
457226947304SEvan Yan 			 * Build unit address.
457326947304SEvan Yan 			 */
457426947304SEvan Yan 			(void) sprintf(unit_address, "%x,%x", device, func);
457526947304SEvan Yan 
457626947304SEvan Yan 			DEBUG3("pci_fc_ops_alloc_handle ap=%lx "
457726947304SEvan Yan 			    "new device=%lx unit address=%s\n",
457826947304SEvan Yan 			    parent, new_child, unit_address);
457926947304SEvan Yan 
458026947304SEvan Yan 			c = pci_fc_ops_alloc_handle(parent, new_child,
458126947304SEvan Yan 			    fcode_addr, fcode_size, unit_address, &po);
458226947304SEvan Yan 
458326947304SEvan Yan 			DEBUG0("calling fcode_interpreter()\n");
458426947304SEvan Yan 
458526947304SEvan Yan 			DEBUG3("Before int DIP=%lx binding name %s major %d\n",
458626947304SEvan Yan 			    new_child, ddi_binding_name(new_child),
458726947304SEvan Yan 			    ddi_driver_major(new_child));
458826947304SEvan Yan 
458926947304SEvan Yan 			error = fcode_interpreter(parent, &pci_fc_ops, c);
459026947304SEvan Yan 
459126947304SEvan Yan 			DEBUG1("returned from fcode_interpreter() - "
459226947304SEvan Yan 			    "returned %x\n", error);
459326947304SEvan Yan 
459426947304SEvan Yan 			pci_fc_ops_free_handle(c);
459526947304SEvan Yan 
459626947304SEvan Yan 			DEBUG1("fcode size = %x\n", fcode_size);
459726947304SEvan Yan 			/*
459826947304SEvan Yan 			 * We don't need the fcode anymore. While allocating
459926947304SEvan Yan 			 * we had rounded up to a page size.
460026947304SEvan Yan 			 */
460126947304SEvan Yan 			if (fcode_size) {
460226947304SEvan Yan 				kmem_free(fcode_addr, ptob(btopr(fcode_size)));
460326947304SEvan Yan 			}
460426947304SEvan Yan 		} else {
460526947304SEvan Yan 			/* This platform does not support fcode */
460626947304SEvan Yan 
460726947304SEvan Yan 			DEBUG0("NOT calling fcode_interpreter()\n");
460826947304SEvan Yan 		}
460926947304SEvan Yan 
461026947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */
461126947304SEvan Yan 
461226947304SEvan Yan 		if ((error == 0) && (pcicfg_dont_interpret == 0)) {
461326947304SEvan Yan 			/*
461426947304SEvan Yan 			 * The interpreter completed successfully.
461526947304SEvan Yan 			 * We need to redo the resources based on the new reg
461626947304SEvan Yan 			 * property.
461726947304SEvan Yan 			 */
461826947304SEvan Yan 			DEBUG3("DIP=%lx binding name %s major %d\n", new_child,
461926947304SEvan Yan 			    ddi_binding_name(new_child),
462026947304SEvan Yan 			    ddi_driver_major(new_child));
462126947304SEvan Yan 
462226947304SEvan Yan 			/*
462326947304SEvan Yan 			 * Readjust resources specified by reg property.
462426947304SEvan Yan 			 */
462526947304SEvan Yan 			if (pcicfg_alloc_new_resources(new_child) ==
462626947304SEvan Yan 			    PCICFG_FAILURE) {
462726947304SEvan Yan 				ret = PCICFG_FAILURE;
462826947304SEvan Yan 				goto failed;
462926947304SEvan Yan 			}
463026947304SEvan Yan 
463126947304SEvan Yan 			/*
463226947304SEvan Yan 			 * At this stage, there should be enough info to pull
463326947304SEvan Yan 			 * the status property if it exists.
463426947304SEvan Yan 			 */
463526947304SEvan Yan 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY,
463626947304SEvan Yan 			    new_child, NULL, "status", &status_prop) ==
463726947304SEvan Yan 			    DDI_PROP_SUCCESS) {
463826947304SEvan Yan 				if ((strncmp("disabled", status_prop, 8) ==
463926947304SEvan Yan 				    0) || (strncmp("fail", status_prop, 4) ==
464026947304SEvan Yan 				    0)) {
464126947304SEvan Yan 					ret = PCICFG_FAILURE;
464226947304SEvan Yan 					ddi_prop_free(status_prop);
464326947304SEvan Yan 					goto failed;
464426947304SEvan Yan 				} else {
464526947304SEvan Yan 					ddi_prop_free(status_prop);
464626947304SEvan Yan 				}
464726947304SEvan Yan 			}
464826947304SEvan Yan 
464926947304SEvan Yan 			ret = PCICFG_SUCCESS;
465026947304SEvan Yan 			/* no fcode, bind driver now */
465126947304SEvan Yan 			(void) ndi_devi_bind_driver(new_child, 0);
465226947304SEvan Yan 
465326947304SEvan Yan 			goto done;
465426947304SEvan Yan 		} else if ((error != FC_NO_FCODE) &&
465526947304SEvan Yan 		    (pcicfg_dont_interpret == 0))  {
465626947304SEvan Yan 			/*
465726947304SEvan Yan 			 * The interpreter located fcode, but had an error in
465826947304SEvan Yan 			 * processing. Cleanup and fail the operation.
465926947304SEvan Yan 			 */
466026947304SEvan Yan 			DEBUG0("Interpreter detected fcode failure\n");
466126947304SEvan Yan 			(void) pcicfg_free_resources(new_child, flags);
466226947304SEvan Yan 			ret = PCICFG_FAILURE;
466326947304SEvan Yan 			goto failed;
466426947304SEvan Yan 		} else {
466526947304SEvan Yan no_fcode:
466626947304SEvan Yan 			/*
466726947304SEvan Yan 			 * Either the interpreter failed with FC_NO_FCODE or we
466826947304SEvan Yan 			 * chose not to run the interpreter
466926947304SEvan Yan 			 * (pcicfg_dont_interpret).
467026947304SEvan Yan 			 *
467126947304SEvan Yan 			 * If the interpreter failed because there was no
467226947304SEvan Yan 			 * dropin, then we need to probe the device ourself.
467326947304SEvan Yan 			 */
467426947304SEvan Yan 
467526947304SEvan Yan 			/*
467626947304SEvan Yan 			 * Free any resources that may have been assigned
467726947304SEvan Yan 			 * during fcode loading/execution since we need
467826947304SEvan Yan 			 * to start over.
467926947304SEvan Yan 			 */
468026947304SEvan Yan 			(void) pcicfg_free_resources(new_child, flags);
468126947304SEvan Yan 
468226947304SEvan Yan #ifdef	EFCODE21554
468326947304SEvan Yan 			pcicfg_config_teardown(&h);
468426947304SEvan Yan #else
468526947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
468626947304SEvan Yan #endif
4687c0da6274SZhi-Jun Robin Fu 			/* destroy the bus_t before the dev node is gone */
4688c0da6274SZhi-Jun Robin Fu 			if (is_pcie)
4689c0da6274SZhi-Jun Robin Fu 				pcie_fini_bus(new_child, PCIE_BUS_FINAL);
4690c0da6274SZhi-Jun Robin Fu 
469126947304SEvan Yan 			(void) ndi_devi_free(new_child);
469226947304SEvan Yan 
469326947304SEvan Yan 			DEBUG0("No Drop-in Probe device ourself\n");
469426947304SEvan Yan 
469526947304SEvan Yan 			ret = pcicfg_probe_children(parent, bus, device, func,
4696c0da6274SZhi-Jun Robin Fu 			    highest_bus, flags, is_pcie);
469726947304SEvan Yan 
469826947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
469926947304SEvan Yan 				DEBUG0("Could not self probe child\n");
470026947304SEvan Yan 				goto failed2;
470126947304SEvan Yan 			}
470226947304SEvan Yan 
470326947304SEvan Yan 			/*
470426947304SEvan Yan 			 * We successfully self probed the device.
470526947304SEvan Yan 			 */
470626947304SEvan Yan 			if ((new_child = pcicfg_devi_find(
470726947304SEvan Yan 			    parent, device, func)) == NULL) {
470826947304SEvan Yan 				DEBUG0("Did'nt find device node "
470926947304SEvan Yan 				    "just created\n");
471026947304SEvan Yan 				ret = PCICFG_FAILURE;
471126947304SEvan Yan 				goto failed2;
471226947304SEvan Yan 			}
471326947304SEvan Yan #ifdef	EFCODE21554
471426947304SEvan Yan 			/*
471526947304SEvan Yan 			 * Till now, we have detected a non transparent bridge
471626947304SEvan Yan 			 * (ntbridge) as a part of the generic probe code and
471726947304SEvan Yan 			 * configured only one configuration
471826947304SEvan Yan 			 * header which is the side facing the host bus.
471926947304SEvan Yan 			 * Now, configure the other side and create children.
472026947304SEvan Yan 			 *
472126947304SEvan Yan 			 * To make the process simpler, lets load the device
472226947304SEvan Yan 			 * driver for the non transparent bridge as this is a
472326947304SEvan Yan 			 * Solaris bundled driver, and use its configuration map
472426947304SEvan Yan 			 * services rather than programming it here.
472526947304SEvan Yan 			 * If the driver is not bundled into Solaris, it must be
472626947304SEvan Yan 			 * first loaded and configured before performing any
472726947304SEvan Yan 			 * hotplug operations.
472826947304SEvan Yan 			 *
472926947304SEvan Yan 			 * This not only makes the code simpler but also more
473026947304SEvan Yan 			 * generic.
473126947304SEvan Yan 			 *
473226947304SEvan Yan 			 * So here we go.
473326947304SEvan Yan 			 */
473426947304SEvan Yan 			if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) {
473526947304SEvan Yan 
473626947304SEvan Yan 				DEBUG0("Found nontransparent bridge.\n");
473726947304SEvan Yan 
473826947304SEvan Yan 				ret = pcicfg_configure_ntbridge(new_child,
473926947304SEvan Yan 				    bus, device);
474026947304SEvan Yan 			}
474126947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
474226947304SEvan Yan 				/*
474326947304SEvan Yan 				 * Bridge configure failed. Free up the self
474426947304SEvan Yan 				 * probed entry. The bus resource allocation
474526947304SEvan Yan 				 * maps need to be cleaned up to prevent
474626947304SEvan Yan 				 * warnings on retries of the failed configure.
474726947304SEvan Yan 				 */
474826947304SEvan Yan 				(void) pcicfg_ntbridge_unconfigure(new_child);
4749c0da6274SZhi-Jun Robin Fu 				(void) pcicfg_teardown_device(new_child,
4750c0da6274SZhi-Jun Robin Fu 				    flags, is_pcie);
475126947304SEvan Yan 			}
475226947304SEvan Yan #endif
475326947304SEvan Yan 			goto done2;
475426947304SEvan Yan 		}
475526947304SEvan Yan 	}
475626947304SEvan Yan done:
475726947304SEvan Yan failed:
4758c0da6274SZhi-Jun Robin Fu 	if (is_pcie) {
4759c0da6274SZhi-Jun Robin Fu 		if (ret == PCICFG_SUCCESS)
4760c1374a13SSurya Prakki 			(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
4761c0da6274SZhi-Jun Robin Fu 		else
4762c0da6274SZhi-Jun Robin Fu 			pcie_fini_bus(new_child, PCIE_BUS_FINAL);
4763c0da6274SZhi-Jun Robin Fu 	}
4764c0da6274SZhi-Jun Robin Fu 
476526947304SEvan Yan #ifdef	EFCODE21554
476626947304SEvan Yan 	pcicfg_config_teardown(&h);
476726947304SEvan Yan #else
476826947304SEvan Yan 	pcicfg_unmap_phys(&h, &p);
476926947304SEvan Yan #endif
477026947304SEvan Yan failed3:
477126947304SEvan Yan 	if (ret != PCICFG_SUCCESS)
477226947304SEvan Yan 		(void) ndi_devi_free(new_child);
477326947304SEvan Yan done2:
477426947304SEvan Yan failed2:
477526947304SEvan Yan 	if (parent_regs.pcie_dev) {
477626947304SEvan Yan 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
477726947304SEvan Yan 			pcicfg_enable_bridge_probe_err(parent,
477826947304SEvan Yan 			    ph, &parent_regs);
477926947304SEvan Yan 		}
478026947304SEvan Yan 		pci_config_teardown(&ph);
478126947304SEvan Yan 	}
4782c0da6274SZhi-Jun Robin Fu 
478326947304SEvan Yan 	return (ret);
478426947304SEvan Yan }
478526947304SEvan Yan 
478626947304SEvan Yan /*
478726947304SEvan Yan  * Read the BARs and update properties. Used in virtual hotplug.
478826947304SEvan Yan  */
478926947304SEvan Yan static int
479026947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child,
479126947304SEvan Yan     ddi_acc_handle_t config_handle)
479226947304SEvan Yan {
479326947304SEvan Yan 	uint32_t request, base, base_hi, size;
479426947304SEvan Yan 	int i;
479526947304SEvan Yan 
479626947304SEvan Yan 	i = PCI_CONF_BASE0;
479726947304SEvan Yan 
479826947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
479926947304SEvan Yan 		/*
480026947304SEvan Yan 		 * determine the size of the address space
480126947304SEvan Yan 		 */
480226947304SEvan Yan 		base = pci_config_get32(config_handle, i);
480326947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
480426947304SEvan Yan 		request = pci_config_get32(config_handle, i);
480526947304SEvan Yan 		pci_config_put32(config_handle, i, base);
480626947304SEvan Yan 
480726947304SEvan Yan 		/*
480826947304SEvan Yan 		 * If its a zero length, don't do any programming.
480926947304SEvan Yan 		 */
481026947304SEvan Yan 		if (request != 0) {
481126947304SEvan Yan 			/*
481226947304SEvan Yan 			 * Add to the "reg" property
481326947304SEvan Yan 			 */
481426947304SEvan Yan 			if (pcicfg_update_reg_prop(new_child,
481526947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
481626947304SEvan Yan 				goto failedchild;
481726947304SEvan Yan 			}
481826947304SEvan Yan 
481926947304SEvan Yan 			if ((PCI_BASE_SPACE_IO & request) == 0 &&
482026947304SEvan Yan 			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
482126947304SEvan Yan 				base_hi = pci_config_get32(config_handle, i+4);
482226947304SEvan Yan 			} else {
482326947304SEvan Yan 				base_hi = 0;
482426947304SEvan Yan 			}
482526947304SEvan Yan 			/*
482626947304SEvan Yan 			 * Add to "assigned-addresses" property
482726947304SEvan Yan 			 */
482826947304SEvan Yan 			size = (~(PCI_BASE_M_ADDR_M & request))+1;
482926947304SEvan Yan 			if (pcicfg_update_assigned_prop_value(new_child,
483026947304SEvan Yan 			    size, base, base_hi, i) != PCICFG_SUCCESS) {
483126947304SEvan Yan 				goto failedchild;
483226947304SEvan Yan 			}
483326947304SEvan Yan 		} else {
483426947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for "
483526947304SEvan Yan 			"[0x0]=[0x0](32)\n", i);
483626947304SEvan Yan 			i += 4;
483726947304SEvan Yan 			continue;
483826947304SEvan Yan 		}
483926947304SEvan Yan 
484026947304SEvan Yan 		/*
484126947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
484226947304SEvan Yan 		 */
484326947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
484426947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
484526947304SEvan Yan 			"[0x%x]=[0x%x] (64)\n",
484626947304SEvan Yan 			    i, request,
484726947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
484826947304SEvan Yan 			i += 8;
484926947304SEvan Yan 		} else {
485026947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
485126947304SEvan Yan 			"[0x%x]=[0x%x](32)\n",
485226947304SEvan Yan 			    i, request,
485326947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request))+1)
485426947304SEvan Yan 			i += 4;
485526947304SEvan Yan 		}
485626947304SEvan Yan 	}
485726947304SEvan Yan 
485826947304SEvan Yan 	/*
485926947304SEvan Yan 	 * Get the ROM size and create register for it
486026947304SEvan Yan 	 */
486126947304SEvan Yan 	base = pci_config_get32(config_handle, PCI_CONF_ROM);
486226947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
486326947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
486426947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, base);
486526947304SEvan Yan 
486626947304SEvan Yan 	/*
486726947304SEvan Yan 	 * If its a zero length, don't do
486826947304SEvan Yan 	 * any programming.
486926947304SEvan Yan 	 */
487026947304SEvan Yan 	if (request != 0) {
487126947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
487226947304SEvan Yan 		    PCI_CONF_ROM, request,
487326947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
487426947304SEvan Yan 		/*
487526947304SEvan Yan 		 * Add to the "reg" property
487626947304SEvan Yan 		 */
487726947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child,
487826947304SEvan Yan 		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
487926947304SEvan Yan 			goto failedchild;
488026947304SEvan Yan 		}
488126947304SEvan Yan 		/*
488226947304SEvan Yan 		 * Add to "assigned-addresses" property
488326947304SEvan Yan 		 */
488426947304SEvan Yan 		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
488526947304SEvan Yan 		if (pcicfg_update_assigned_prop_value(new_child, size,
488626947304SEvan Yan 		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
488726947304SEvan Yan 			goto failedchild;
488826947304SEvan Yan 		}
488926947304SEvan Yan 	}
489026947304SEvan Yan 
489126947304SEvan Yan 	return (PCICFG_SUCCESS);
489226947304SEvan Yan 
489326947304SEvan Yan failedchild:
489426947304SEvan Yan 	return (PCICFG_FAILURE);
489526947304SEvan Yan }
489626947304SEvan Yan 
489726947304SEvan Yan static int
489826947304SEvan Yan pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
4899c0da6274SZhi-Jun Robin Fu 	uint_t *highest_bus, boolean_t is_pcie)
490026947304SEvan Yan {
490126947304SEvan Yan 	uint64_t next_bus;
490226947304SEvan Yan 	uint_t new_bus, num_slots;
490326947304SEvan Yan 	ndi_ra_request_t req;
490426947304SEvan Yan 	int rval, i, j;
490526947304SEvan Yan 	uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end;
490626947304SEvan Yan 	uint64_t io_answer, io_base, io_alen, io_size, io_end;
490726947304SEvan Yan 	uint64_t round_answer, round_len;
490826947304SEvan Yan 	pcicfg_range_t range[PCICFG_RANGE_LEN];
490926947304SEvan Yan 	int bus_range[2];
491026947304SEvan Yan 	pcicfg_phdl_t phdl;
491126947304SEvan Yan 	int count;
491226947304SEvan Yan 	uint64_t pcibus_base, pcibus_alen;
491326947304SEvan Yan 	uint64_t max_bus;
491426947304SEvan Yan 	uint8_t pcie_device_type = 0;
491526947304SEvan Yan 	dev_info_t *new_device;
491626947304SEvan Yan 	int trans_device;
491726947304SEvan Yan 	int ari_mode = B_FALSE;
491826947304SEvan Yan 	int max_function = PCICFG_MAX_FUNCTION;
491926947304SEvan Yan 
492026947304SEvan Yan 	/*
492126947304SEvan Yan 	 * Set "device_type" to "pci", the actual type will be set later
492226947304SEvan Yan 	 * by pcicfg_set_busnode_props() below. This is needed as the
492326947304SEvan Yan 	 * pcicfg_ra_free() below would update "available" property based
492426947304SEvan Yan 	 * on "device_type".
492526947304SEvan Yan 	 *
492626947304SEvan Yan 	 * This code can be removed later after PCI configurator is changed
492726947304SEvan Yan 	 * to use PCIRM, which automatically update properties upon allocation
492826947304SEvan Yan 	 * and free, at that time we'll be able to remove the code inside
492926947304SEvan Yan 	 * ndi_ra_alloc/free() which currently updates "available" property
493026947304SEvan Yan 	 * for pci/pcie devices in pcie fabric.
493126947304SEvan Yan 	 */
493226947304SEvan Yan 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
493326947304SEvan Yan 	    "device_type", "pci") != DDI_SUCCESS) {
493426947304SEvan Yan 		DEBUG0("Failed to set \"device_type\" props\n");
493526947304SEvan Yan 		return (PCICFG_FAILURE);
493626947304SEvan Yan 	}
493726947304SEvan Yan 
493826947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
493926947304SEvan Yan 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
494026947304SEvan Yan 	req.ra_boundbase = 0;
494126947304SEvan Yan 	req.ra_boundlen = PCICFG_MAX_BUS_DEPTH;
494226947304SEvan Yan 	req.ra_len = PCICFG_MAX_BUS_DEPTH;
494326947304SEvan Yan 	req.ra_align_mask = 0;  /* no alignment needed */
494426947304SEvan Yan 
494526947304SEvan Yan 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
494626947304SEvan Yan 	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
494726947304SEvan Yan 
494826947304SEvan Yan 	if (rval != NDI_SUCCESS) {
494926947304SEvan Yan 		if (rval == NDI_RA_PARTIAL_REQ) {
495026947304SEvan Yan 			/*EMPTY*/
495126947304SEvan Yan 			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
495226947304SEvan Yan 		} else {
495326947304SEvan Yan 			DEBUG0(
495426947304SEvan Yan 			    "Failed to allocate bus range for bridge\n");
495526947304SEvan Yan 			return (PCICFG_FAILURE);
495626947304SEvan Yan 		}
495726947304SEvan Yan 	}
495826947304SEvan Yan 
495926947304SEvan Yan 	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
496026947304SEvan Yan 	    pcibus_base, pcibus_alen);
496126947304SEvan Yan 
496226947304SEvan Yan 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
496326947304SEvan Yan 	    == NDI_FAILURE) {
496426947304SEvan Yan 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
496526947304SEvan Yan 		return (PCICFG_FAILURE);
496626947304SEvan Yan 	}
496726947304SEvan Yan 
496826947304SEvan Yan 	/*
496926947304SEvan Yan 	 * Put available bus range into the pool.
497026947304SEvan Yan 	 * Take the first one for this bridge to use and don't give
497126947304SEvan Yan 	 * to child.
497226947304SEvan Yan 	 */
497326947304SEvan Yan 	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
497426947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
497526947304SEvan Yan 
497626947304SEvan Yan 	next_bus = pcibus_base;
497726947304SEvan Yan 	max_bus = pcibus_base + pcibus_alen - 1;
497826947304SEvan Yan 
497926947304SEvan Yan 	new_bus = next_bus;
498026947304SEvan Yan 
498126947304SEvan Yan 	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
498226947304SEvan Yan 
498326947304SEvan Yan 	/* Keep track of highest bus for subordinate bus programming */
498426947304SEvan Yan 	*highest_bus = new_bus;
498526947304SEvan Yan 
498626947304SEvan Yan 	/*
498726947304SEvan Yan 	 * Allocate Memory Space for Bridge
498826947304SEvan Yan 	 */
498926947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
499026947304SEvan Yan 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
499126947304SEvan Yan 	req.ra_boundbase = 0;
499226947304SEvan Yan 	/*
499326947304SEvan Yan 	 * Note: To support a 32b system, boundlen and len need to be
499426947304SEvan Yan 	 * 32b quantities
499526947304SEvan Yan 	 */
499626947304SEvan Yan 	req.ra_boundlen = PCICFG_4GIG_LIMIT + 1;
499726947304SEvan Yan 	req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */
499826947304SEvan Yan 	req.ra_align_mask =
499926947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
500026947304SEvan Yan 
500126947304SEvan Yan 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
500226947304SEvan Yan 	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
500326947304SEvan Yan 
500426947304SEvan Yan 	if (rval != NDI_SUCCESS) {
500526947304SEvan Yan 		if (rval == NDI_RA_PARTIAL_REQ) {
500626947304SEvan Yan 			/*EMPTY*/
500726947304SEvan Yan 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
500826947304SEvan Yan 		} else {
500926947304SEvan Yan 			DEBUG0(
501026947304SEvan Yan 			    "Failed to allocate memory for bridge\n");
501126947304SEvan Yan 			return (PCICFG_FAILURE);
501226947304SEvan Yan 		}
501326947304SEvan Yan 	}
501426947304SEvan Yan 
501526947304SEvan Yan 	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
501626947304SEvan Yan 	    PCICFG_HIADDR(mem_answer),
501726947304SEvan Yan 	    PCICFG_LOADDR(mem_answer),
501826947304SEvan Yan 	    mem_alen);
501926947304SEvan Yan 
502026947304SEvan Yan 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
502126947304SEvan Yan 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
502226947304SEvan Yan 		return (PCICFG_FAILURE);
502326947304SEvan Yan 	}
502426947304SEvan Yan 
502526947304SEvan Yan 	/*
502626947304SEvan Yan 	 * Put available memory into the pool.
502726947304SEvan Yan 	 */
502826947304SEvan Yan 	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
502926947304SEvan Yan 	    NDI_RA_PASS);
503026947304SEvan Yan 
503126947304SEvan Yan 	mem_base = mem_answer;
503226947304SEvan Yan 
503326947304SEvan Yan 	/*
503426947304SEvan Yan 	 * Allocate I/O Space for Bridge
503526947304SEvan Yan 	 */
503626947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
503726947304SEvan Yan 	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
503826947304SEvan Yan 	req.ra_boundbase = 0;
503926947304SEvan Yan 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
504026947304SEvan Yan 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
504126947304SEvan Yan 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
504226947304SEvan Yan 
504326947304SEvan Yan 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
504426947304SEvan Yan 	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
504526947304SEvan Yan 
504626947304SEvan Yan 	if (rval != NDI_SUCCESS) {
504726947304SEvan Yan 		if (rval == NDI_RA_PARTIAL_REQ) {
504826947304SEvan Yan 			/*EMPTY*/
504926947304SEvan Yan 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
505026947304SEvan Yan 		} else {
505126947304SEvan Yan 			DEBUG0("Failed to allocate io space for bridge\n");
505226947304SEvan Yan 			io_base = io_answer = io_alen = 0;
505326947304SEvan Yan 			/* return (PCICFG_FAILURE); */
505426947304SEvan Yan 		}
505526947304SEvan Yan 	}
505626947304SEvan Yan 
505726947304SEvan Yan 	if (io_alen) {
505826947304SEvan Yan 		DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
505926947304SEvan Yan 		    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer),
506026947304SEvan Yan 		    io_alen);
506126947304SEvan Yan 
506226947304SEvan Yan 		if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) ==
506326947304SEvan Yan 		    NDI_FAILURE) {
506426947304SEvan Yan 			DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
506526947304SEvan Yan 			return (PCICFG_FAILURE);
506626947304SEvan Yan 		}
506726947304SEvan Yan 
506826947304SEvan Yan 		/*
506926947304SEvan Yan 		 * Put available I/O into the pool.
507026947304SEvan Yan 		 */
507126947304SEvan Yan 		(void) ndi_ra_free(new_child, io_answer, io_alen,
507226947304SEvan Yan 		    NDI_RA_TYPE_IO, NDI_RA_PASS);
507326947304SEvan Yan 		io_base = io_answer;
507426947304SEvan Yan 	}
507526947304SEvan Yan 
507626947304SEvan Yan 	pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
507726947304SEvan Yan 
507826947304SEvan Yan 	/*
507926947304SEvan Yan 	 * Setup "bus-range" property before onlining the bridge.
508026947304SEvan Yan 	 */
508126947304SEvan Yan 	bus_range[0] = new_bus;
508226947304SEvan Yan 	bus_range[1] = max_bus;
508326947304SEvan Yan 
508426947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
508526947304SEvan Yan 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
508626947304SEvan Yan 		DEBUG0("Failed to set bus-range property");
508726947304SEvan Yan 		return (PCICFG_FAILURE);
508826947304SEvan Yan 	}
508926947304SEvan Yan 
509026947304SEvan Yan 	/*
509126947304SEvan Yan 	 * Reset the secondary bus
509226947304SEvan Yan 	 */
509326947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL,
509426947304SEvan Yan 	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
509526947304SEvan Yan 
509626947304SEvan Yan 	drv_usecwait(100);
509726947304SEvan Yan 
509826947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_BCNTRL,
509926947304SEvan Yan 	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
510026947304SEvan Yan 
510126947304SEvan Yan 	/*
510226947304SEvan Yan 	 * Program the memory base register with the
510326947304SEvan Yan 	 * start of the memory range
510426947304SEvan Yan 	 */
510526947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_MEM_BASE,
510626947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
510726947304SEvan Yan 
510826947304SEvan Yan 	/*
510926947304SEvan Yan 	 * Program the memory limit register with the
511026947304SEvan Yan 	 * end of the memory range.
511126947304SEvan Yan 	 */
511226947304SEvan Yan 
511326947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
511426947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(
511526947304SEvan Yan 	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
511626947304SEvan Yan 
511726947304SEvan Yan 	/*
511826947304SEvan Yan 	 * Allocate the chunk of memory (if any) not programmed into the
511926947304SEvan Yan 	 * bridge because of the round down.
512026947304SEvan Yan 	 */
512126947304SEvan Yan 	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
512226947304SEvan Yan 	    != (mem_answer + mem_alen)) {
512326947304SEvan Yan 		DEBUG0("Need to allocate Memory round off chunk\n");
512426947304SEvan Yan 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
512526947304SEvan Yan 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
512626947304SEvan Yan 		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
512726947304SEvan Yan 		    PCICFG_MEMGRAN);
512826947304SEvan Yan 		req.ra_len =  (mem_answer + mem_alen) -
512926947304SEvan Yan 		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
513026947304SEvan Yan 		    PCICFG_MEMGRAN));
513126947304SEvan Yan 
513226947304SEvan Yan 		(void) ndi_ra_alloc(new_child, &req,
513326947304SEvan Yan 		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
513426947304SEvan Yan 	}
513526947304SEvan Yan 
513626947304SEvan Yan 	/*
513726947304SEvan Yan 	 * Program the I/O Space Base
513826947304SEvan Yan 	 */
513926947304SEvan Yan 	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
514026947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(
514126947304SEvan Yan 	    PCICFG_LOADDR(io_answer))));
514226947304SEvan Yan 
514326947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
514426947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
514526947304SEvan Yan 
514626947304SEvan Yan 	/*
514726947304SEvan Yan 	 * Program the I/O Space Limit
514826947304SEvan Yan 	 */
514926947304SEvan Yan 	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
515026947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(
515126947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
515226947304SEvan Yan 	    PCICFG_IOGRAN)))) - 1);
515326947304SEvan Yan 
515426947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
515526947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(
515626947304SEvan Yan 	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
515726947304SEvan Yan 	    - 1);
515826947304SEvan Yan 
515926947304SEvan Yan 	/*
516026947304SEvan Yan 	 * Allocate the chunk of I/O (if any) not programmed into the
516126947304SEvan Yan 	 * bridge because of the round down.
516226947304SEvan Yan 	 */
516326947304SEvan Yan 	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
516426947304SEvan Yan 	    != (io_answer + io_alen)) {
516526947304SEvan Yan 		DEBUG0("Need to allocate I/O round off chunk\n");
516626947304SEvan Yan 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
516726947304SEvan Yan 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
516826947304SEvan Yan 		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
516926947304SEvan Yan 		    PCICFG_IOGRAN);
517026947304SEvan Yan 		req.ra_len =  (io_answer + io_alen) -
517126947304SEvan Yan 		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
517226947304SEvan Yan 		    PCICFG_IOGRAN));
517326947304SEvan Yan 
517426947304SEvan Yan 		(void) ndi_ra_alloc(new_child, &req,
517526947304SEvan Yan 		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
517626947304SEvan Yan 	}
517726947304SEvan Yan 
517826947304SEvan Yan 	/*
517926947304SEvan Yan 	 * Setup "ranges" property before onlining the bridge.
518026947304SEvan Yan 	 */
518126947304SEvan Yan 	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
518226947304SEvan Yan 
518326947304SEvan Yan 	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
518426947304SEvan Yan 	range[0].child_lo = range[0].parent_lo = io_base;
518526947304SEvan Yan 	range[1].child_hi = range[1].parent_hi |=
518626947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
518726947304SEvan Yan 	range[1].child_lo = range[1].parent_lo = mem_base;
518826947304SEvan Yan 
518926947304SEvan Yan 	range[0].size_lo = io_alen;
519026947304SEvan Yan 	if (pcicfg_update_ranges_prop(new_child, &range[0])) {
519126947304SEvan Yan 		DEBUG0("Failed to update ranges (io)\n");
519226947304SEvan Yan 		return (PCICFG_FAILURE);
519326947304SEvan Yan 	}
519426947304SEvan Yan 	range[1].size_lo = mem_alen;
519526947304SEvan Yan 	if (pcicfg_update_ranges_prop(new_child, &range[1])) {
519626947304SEvan Yan 		DEBUG0("Failed to update ranges (memory)\n");
519726947304SEvan Yan 		return (PCICFG_FAILURE);
519826947304SEvan Yan 	}
519926947304SEvan Yan 
520026947304SEvan Yan 	/*
520126947304SEvan Yan 	 * Clear status bits
520226947304SEvan Yan 	 */
520326947304SEvan Yan 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
520426947304SEvan Yan 
520526947304SEvan Yan 	/*
520626947304SEvan Yan 	 * Turn off prefetchable range
520726947304SEvan Yan 	 */
520826947304SEvan Yan 	pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
520926947304SEvan Yan 	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
521026947304SEvan Yan 	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
521126947304SEvan Yan 
521226947304SEvan Yan 	/*
521326947304SEvan Yan 	 * Needs to be set to this value
521426947304SEvan Yan 	 */
521526947304SEvan Yan 	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
521626947304SEvan Yan 
521726947304SEvan Yan 	/* check our device_type as defined by Open Firmware */
521826947304SEvan Yan 	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
521926947304SEvan Yan 		pcie_device_type = 1;
522026947304SEvan Yan 
522126947304SEvan Yan 	/*
522226947304SEvan Yan 	 * Set bus properties
522326947304SEvan Yan 	 */
522426947304SEvan Yan 	if (pcicfg_set_busnode_props(new_child, pcie_device_type,
522526947304SEvan Yan 	    (int)bus, (int)new_bus) != PCICFG_SUCCESS) {
522626947304SEvan Yan 		DEBUG0("Failed to set busnode props\n");
522726947304SEvan Yan 		return (PCICFG_FAILURE);
522826947304SEvan Yan 	}
522926947304SEvan Yan 
523026947304SEvan Yan 	(void) pcicfg_device_on(h);
523126947304SEvan Yan 
5232c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
5233c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
523426947304SEvan Yan 	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
523526947304SEvan Yan 	    != NDI_SUCCESS) {
523626947304SEvan Yan 		DEBUG0("Unable to online bridge\n");
523726947304SEvan Yan 		return (PCICFG_FAILURE);
523826947304SEvan Yan 	}
523926947304SEvan Yan 
524026947304SEvan Yan 	DEBUG0("Bridge is ONLINE\n");
524126947304SEvan Yan 
524226947304SEvan Yan 	/*
524326947304SEvan Yan 	 * After a Reset, we need to wait 2^25 clock cycles before the
524426947304SEvan Yan 	 * first Configuration access.  The worst case is 33MHz, which
524526947304SEvan Yan 	 * is a 1 second wait.
524626947304SEvan Yan 	 */
524726947304SEvan Yan 	drv_usecwait(pcicfg_sec_reset_delay);
524826947304SEvan Yan 
524926947304SEvan Yan 	/*
525026947304SEvan Yan 	 * Probe all children devices
525126947304SEvan Yan 	 */
525226947304SEvan Yan 	DEBUG0("Bridge Programming Complete - probe children\n");
525326947304SEvan Yan 	ndi_devi_enter(new_child, &count);
525426947304SEvan Yan 	for (i = 0; ((i < PCICFG_MAX_DEVICE) && (ari_mode == B_FALSE));
525526947304SEvan Yan 	    i++) {
525626947304SEvan Yan 		for (j = 0; j < max_function; ) {
525726947304SEvan Yan 			if (ari_mode)
525826947304SEvan Yan 				trans_device = j >> 3;
525926947304SEvan Yan 			else
526026947304SEvan Yan 				trans_device = i;
526126947304SEvan Yan 
526226947304SEvan Yan 			if ((rval = pcicfg_fcode_probe(new_child,
5263c0da6274SZhi-Jun Robin Fu 			    new_bus, trans_device, (j & 7), highest_bus,
5264c0da6274SZhi-Jun Robin Fu 			    0, is_pcie))
526526947304SEvan Yan 			    != PCICFG_SUCCESS) {
526626947304SEvan Yan 				if (rval == PCICFG_NODEVICE) {
526726947304SEvan Yan 					DEBUG3("No Device at bus [0x%x]"
526826947304SEvan Yan 					    "device [0x%x] "
526926947304SEvan Yan 					    "func [0x%x]\n", new_bus,
527026947304SEvan Yan 					    trans_device, j & 7);
527126947304SEvan Yan 
527226947304SEvan Yan 					if (j)
527326947304SEvan Yan 						goto next;
527426947304SEvan Yan 				} else {
527526947304SEvan Yan 					DEBUG3("Failed to configure bus "
527626947304SEvan Yan 					    "[0x%x] device [0x%x] "
527726947304SEvan Yan 					    "func [0x%x]\n", new_bus,
527826947304SEvan Yan 					    trans_device, j & 7);
527926947304SEvan Yan 
528026947304SEvan Yan 					rval = PCICFG_FAILURE;
528126947304SEvan Yan 				}
528226947304SEvan Yan 				break;
528326947304SEvan Yan 			}
528426947304SEvan Yan next:
528526947304SEvan Yan 			new_device = pcicfg_devi_find(new_child,
528626947304SEvan Yan 			    trans_device, (j & 7));
528726947304SEvan Yan 
528826947304SEvan Yan 			/*
528926947304SEvan Yan 			 * Determine if ARI Forwarding should be enabled.
529026947304SEvan Yan 			 */
529126947304SEvan Yan 			if (j == 0) {
529226947304SEvan Yan 				if (new_device == NULL)
529326947304SEvan Yan 					break;
529426947304SEvan Yan 
529526947304SEvan Yan 				if ((pcie_ari_supported(new_child) ==
529626947304SEvan Yan 				    PCIE_ARI_FORW_ENABLED) &&
529726947304SEvan Yan 				    (pcie_ari_device(new_device) ==
529826947304SEvan Yan 				    PCIE_ARI_DEVICE)) {
529926947304SEvan Yan 					if (pcie_ari_enable(new_child) ==
530026947304SEvan Yan 					    DDI_SUCCESS) {
530126947304SEvan Yan 						(void) ddi_prop_create(
530226947304SEvan Yan 						    DDI_DEV_T_NONE,
530326947304SEvan Yan 						    new_child,
530426947304SEvan Yan 						    DDI_PROP_CANSLEEP,
530526947304SEvan Yan 						    "ari-enabled", NULL, 0);
530626947304SEvan Yan 						ari_mode = B_TRUE;
530726947304SEvan Yan 						max_function =
530826947304SEvan Yan 						    PCICFG_MAX_ARI_FUNCTION;
530926947304SEvan Yan 					}
531026947304SEvan Yan 				}
531126947304SEvan Yan 			}
531226947304SEvan Yan 
531326947304SEvan Yan 			if (ari_mode == B_TRUE) {
531426947304SEvan Yan 				int next_function;
531526947304SEvan Yan 
531626947304SEvan Yan 				if (new_device == NULL)
531726947304SEvan Yan 					break;
531826947304SEvan Yan 
531926947304SEvan Yan 				if (pcie_ari_get_next_function(new_device,
532026947304SEvan Yan 				    &next_function) != DDI_SUCCESS)
532126947304SEvan Yan 					break;
532226947304SEvan Yan 
532326947304SEvan Yan 				j = next_function;
532426947304SEvan Yan 
532526947304SEvan Yan 				if (next_function == 0)
532626947304SEvan Yan 					break;
532726947304SEvan Yan 			} else
532826947304SEvan Yan 				j++;
532926947304SEvan Yan 		}
533026947304SEvan Yan 	}
533126947304SEvan Yan 
533226947304SEvan Yan 	ndi_devi_exit(new_child, count);
533326947304SEvan Yan 
533426947304SEvan Yan 	/* if empty topology underneath, it is still a success. */
533526947304SEvan Yan 	if (rval != PCICFG_FAILURE)
533626947304SEvan Yan 		rval = PCICFG_SUCCESS;
533726947304SEvan Yan 
533826947304SEvan Yan 	/*
533926947304SEvan Yan 	 * Offline the bridge to allow reprogramming of resources.
534026947304SEvan Yan 	 *
534126947304SEvan Yan 	 * This should always succeed since nobody else has started to
534226947304SEvan Yan 	 * use it yet, failing to detach the driver would indicate a bug.
534326947304SEvan Yan 	 * Also in that case it's better just panic than allowing the
534426947304SEvan Yan 	 * configurator to proceed with BAR reprogramming without bridge
534526947304SEvan Yan 	 * driver detached.
534626947304SEvan Yan 	 */
534726947304SEvan Yan 	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
534826947304SEvan Yan 	    == NDI_SUCCESS);
5349c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
5350c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
535126947304SEvan Yan 
535226947304SEvan Yan 	phdl.dip = new_child;
535326947304SEvan Yan 	phdl.memory_base = mem_answer;
535426947304SEvan Yan 	phdl.io_base = (uint32_t)io_answer;
535526947304SEvan Yan 	phdl.error = PCICFG_SUCCESS;    /* in case of empty child tree */
535626947304SEvan Yan 
535726947304SEvan Yan 	ndi_devi_enter(ddi_get_parent(new_child), &count);
535826947304SEvan Yan 	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
535926947304SEvan Yan 	ndi_devi_exit(ddi_get_parent(new_child), count);
536026947304SEvan Yan 
536126947304SEvan Yan 	if (phdl.error != PCICFG_SUCCESS) {
536226947304SEvan Yan 		DEBUG0("Failure summing resources\n");
536326947304SEvan Yan 		return (PCICFG_FAILURE);
536426947304SEvan Yan 	}
536526947304SEvan Yan 
536626947304SEvan Yan 	num_slots = pcicfg_get_nslots(new_child, h);
536726947304SEvan Yan 	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
536826947304SEvan Yan 	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
536926947304SEvan Yan 
537026947304SEvan Yan 	DEBUG3("Start of Unallocated Bridge(%d slots) Resources "
537126947304SEvan Yan 	    "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end);
537226947304SEvan Yan 
537326947304SEvan Yan 	/*
537426947304SEvan Yan 	 * Before probing the children we've allocated maximum MEM/IO
537526947304SEvan Yan 	 * resources from parent, and updated "available" property
537626947304SEvan Yan 	 * accordingly. Later we'll be giving up unused resources to
537726947304SEvan Yan 	 * the parent, thus we need to destroy "available" property
537826947304SEvan Yan 	 * here otherwise it will be out-of-sync with the actual free
537926947304SEvan Yan 	 * resources this bridge has. This property will be rebuilt below
538026947304SEvan Yan 	 * with the actual free resources reserved for hotplug slots
538126947304SEvan Yan 	 * (if any).
538226947304SEvan Yan 	 */
538326947304SEvan Yan 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
538426947304SEvan Yan 	/*
538526947304SEvan Yan 	 * if the bridge a slots, then preallocate. If not, assume static
538626947304SEvan Yan 	 * configuration. Also check for preallocation limits and spit
538726947304SEvan Yan 	 * warning messages appropriately (perhaps some can be in debug mode).
538826947304SEvan Yan 	 */
538926947304SEvan Yan 	if (num_slots) {
539026947304SEvan Yan 		pci_regspec_t reg;
539126947304SEvan Yan 		uint64_t mem_assigned = mem_end;
539226947304SEvan Yan 		uint64_t io_assigned = io_end;
539326947304SEvan Yan 		uint64_t mem_reqd = mem_answer + (num_slots *
539426947304SEvan Yan 		    pcicfg_slot_memsize);
539526947304SEvan Yan 		uint64_t io_reqd = io_answer + (num_slots *
539626947304SEvan Yan 		    pcicfg_slot_iosize);
539726947304SEvan Yan 		uint8_t highest_bus_reqd = new_bus + (num_slots *
539826947304SEvan Yan 		    pcicfg_slot_busnums);
539926947304SEvan Yan #ifdef DEBUG
540026947304SEvan Yan 		if (mem_end > mem_reqd)
540126947304SEvan Yan 			DEBUG3("Memory space consumed by bridge"
540226947304SEvan Yan 			    " more than planned for %d slot(s)(%lx, %lx)",
540326947304SEvan Yan 			    num_slots, mem_answer, mem_end);
540426947304SEvan Yan 		if (io_end > io_reqd)
540526947304SEvan Yan 			DEBUG3("IO space consumed by bridge"
540626947304SEvan Yan 			    " more than planned for %d slot(s)(%lx, %lx)",
540726947304SEvan Yan 			    num_slots, io_answer, io_end);
540826947304SEvan Yan 		if (*highest_bus > highest_bus_reqd)
540926947304SEvan Yan 			DEBUG3("Buses consumed by bridge"
541026947304SEvan Yan 			    " more than planned for %d slot(s)(%x, %x)",
541126947304SEvan Yan 			    num_slots, new_bus, *highest_bus);
541226947304SEvan Yan 
541326947304SEvan Yan 		if (mem_reqd > (mem_answer + mem_alen))
541426947304SEvan Yan 			DEBUG3("Memory space required by bridge"
541526947304SEvan Yan 			    " more than available for %d slot(s)(%lx, %lx)",
541626947304SEvan Yan 			    num_slots, mem_answer, mem_end);
541726947304SEvan Yan 
541826947304SEvan Yan 		if (io_reqd > (io_answer + io_alen))
541926947304SEvan Yan 			DEBUG3("IO space required by bridge"
542026947304SEvan Yan 			    " more than available for %d slot(s)(%lx, %lx)",
542126947304SEvan Yan 			    num_slots, io_answer, io_end);
542226947304SEvan Yan 		if (highest_bus_reqd > max_bus)
542326947304SEvan Yan 			DEBUG3("Bus numbers required by bridge"
542426947304SEvan Yan 			    " more than available for %d slot(s)(%x, %x)",
542526947304SEvan Yan 			    num_slots, new_bus, *highest_bus);
542626947304SEvan Yan #endif
542726947304SEvan Yan 		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
542826947304SEvan Yan 		    mem_end);
542926947304SEvan Yan 		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
543026947304SEvan Yan 		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
543126947304SEvan Yan 		    *highest_bus);
543226947304SEvan Yan 		DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n",
543326947304SEvan Yan 		    mem_end, io_end, *highest_bus);
543426947304SEvan Yan 
543526947304SEvan Yan 		mem_size = mem_end - mem_assigned;
543626947304SEvan Yan 		io_size = io_end - io_assigned;
543726947304SEvan Yan 
543826947304SEvan Yan 		reg.pci_phys_mid = reg.pci_size_hi = 0;
543926947304SEvan Yan 		if (io_size > 0) {
544026947304SEvan Yan 			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO);
544126947304SEvan Yan 			reg.pci_phys_low = io_assigned;
544226947304SEvan Yan 			reg.pci_size_low = io_size;
544326947304SEvan Yan 			if (pcicfg_update_available_prop(new_child, &reg)) {
544426947304SEvan Yan 				DEBUG0("Failed to update available prop "
544526947304SEvan Yan 				    "(io)\n");
544626947304SEvan Yan 				return (PCICFG_FAILURE);
544726947304SEvan Yan 			}
544826947304SEvan Yan 		}
544926947304SEvan Yan 		if (mem_size > 0) {
545026947304SEvan Yan 			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32);
545126947304SEvan Yan 			reg.pci_phys_low = mem_assigned;
545226947304SEvan Yan 			reg.pci_size_low = mem_size;
545326947304SEvan Yan 			if (pcicfg_update_available_prop(new_child, &reg)) {
545426947304SEvan Yan 				DEBUG0("Failed to update available prop "
545526947304SEvan Yan 				    "(memory)\n");
545626947304SEvan Yan 				return (PCICFG_FAILURE);
545726947304SEvan Yan 			}
545826947304SEvan Yan 		}
545926947304SEvan Yan 	}
546026947304SEvan Yan 
546126947304SEvan Yan 	/*
546226947304SEvan Yan 	 * Give back unused memory space to parent.
546326947304SEvan Yan 	 */
546426947304SEvan Yan 	(void) ndi_ra_free(ddi_get_parent(new_child),
546526947304SEvan Yan 	    mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
546626947304SEvan Yan 	    NDI_RA_PASS);
546726947304SEvan Yan 
546826947304SEvan Yan 	if (mem_end == mem_answer) {
546926947304SEvan Yan 		DEBUG0("No memory resources used\n");
547026947304SEvan Yan 		/*
547126947304SEvan Yan 		 * To prevent the bridge from forwarding any Memory
547226947304SEvan Yan 		 * transactions, the Memory Limit will be programmed
547326947304SEvan Yan 		 * with a smaller value than the Memory Base.
547426947304SEvan Yan 		 */
547526947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
547626947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
547726947304SEvan Yan 
547826947304SEvan Yan 		mem_size = 0;
547926947304SEvan Yan 	} else {
548026947304SEvan Yan 		/*
548126947304SEvan Yan 		 * Reprogram the end of the memory.
548226947304SEvan Yan 		 */
548326947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
548426947304SEvan Yan 		    PCICFG_HIWORD(mem_end) - 1);
548526947304SEvan Yan 		mem_size = mem_end - mem_base;
548626947304SEvan Yan 	}
548726947304SEvan Yan 
548826947304SEvan Yan 	/*
548926947304SEvan Yan 	 * Give back unused io space to parent.
549026947304SEvan Yan 	 */
549126947304SEvan Yan 	(void) ndi_ra_free(ddi_get_parent(new_child),
549226947304SEvan Yan 	    io_end, (io_answer + io_alen) - io_end,
549326947304SEvan Yan 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
549426947304SEvan Yan 
549526947304SEvan Yan 	if (io_end == io_answer) {
549626947304SEvan Yan 		DEBUG0("No IO Space resources used\n");
549726947304SEvan Yan 
549826947304SEvan Yan 		/*
549926947304SEvan Yan 		 * To prevent the bridge from forwarding any I/O
550026947304SEvan Yan 		 * transactions, the I/O Limit will be programmed
550126947304SEvan Yan 		 * with a smaller value than the I/O Base.
550226947304SEvan Yan 		 */
550326947304SEvan Yan 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
550426947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
550526947304SEvan Yan 		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
550626947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
550726947304SEvan Yan 
550826947304SEvan Yan 		io_size = 0;
550926947304SEvan Yan 	} else {
551026947304SEvan Yan 		/*
551126947304SEvan Yan 		 * Reprogram the end of the io space.
551226947304SEvan Yan 		 */
551326947304SEvan Yan 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
551426947304SEvan Yan 		    PCICFG_HIBYTE(PCICFG_LOWORD(
551526947304SEvan Yan 		    PCICFG_LOADDR(io_end) - 1)));
551626947304SEvan Yan 
551726947304SEvan Yan 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
551826947304SEvan Yan 		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
551926947304SEvan Yan 
552026947304SEvan Yan 		io_size = io_end - io_base;
552126947304SEvan Yan 	}
552226947304SEvan Yan 
552326947304SEvan Yan 	if ((max_bus - *highest_bus) > 0) {
552426947304SEvan Yan 		/*
552526947304SEvan Yan 		 * Give back unused bus numbers
552626947304SEvan Yan 		 */
552726947304SEvan Yan 		(void) ndi_ra_free(ddi_get_parent(new_child),
552826947304SEvan Yan 		    *highest_bus+1, max_bus - *highest_bus,
552926947304SEvan Yan 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
553026947304SEvan Yan 	}
553126947304SEvan Yan 
553226947304SEvan Yan 	/*
553326947304SEvan Yan 	 * Set bus numbers to ranges encountered during scan
553426947304SEvan Yan 	 */
553526947304SEvan Yan 	pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
553626947304SEvan Yan 
553726947304SEvan Yan 	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
553826947304SEvan Yan 	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
553926947304SEvan Yan 	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
554026947304SEvan Yan 	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
554126947304SEvan Yan 
554226947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
554326947304SEvan Yan 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
554426947304SEvan Yan 		DEBUG0("Failed to set bus-range property");
554526947304SEvan Yan 		return (PCICFG_FAILURE);
554626947304SEvan Yan 	}
554726947304SEvan Yan 
554826947304SEvan Yan 	/*
554926947304SEvan Yan 	 * Remove the ranges property if it exists since we will create
555026947304SEvan Yan 	 * a new one.
555126947304SEvan Yan 	 */
555226947304SEvan Yan 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
555326947304SEvan Yan 
555426947304SEvan Yan 	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
555526947304SEvan Yan 	    mem_base, mem_size);
555626947304SEvan Yan 	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
555726947304SEvan Yan 	    io_base, io_size);
555826947304SEvan Yan 
555926947304SEvan Yan 	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
556026947304SEvan Yan 
556126947304SEvan Yan 	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
556226947304SEvan Yan 	range[0].child_lo = range[0].parent_lo = io_base;
556326947304SEvan Yan 	range[1].child_hi = range[1].parent_hi |=
556426947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
556526947304SEvan Yan 	range[1].child_lo = range[1].parent_lo = mem_base;
556626947304SEvan Yan 
556726947304SEvan Yan 	if (io_size > 0) {
556826947304SEvan Yan 		range[0].size_lo = io_size;
556926947304SEvan Yan 		if (pcicfg_update_ranges_prop(new_child, &range[0])) {
557026947304SEvan Yan 			DEBUG0("Failed to update ranges (io)\n");
557126947304SEvan Yan 			return (PCICFG_FAILURE);
557226947304SEvan Yan 		}
557326947304SEvan Yan 	}
557426947304SEvan Yan 	if (mem_size > 0) {
557526947304SEvan Yan 		range[1].size_lo = mem_size;
557626947304SEvan Yan 		if (pcicfg_update_ranges_prop(new_child, &range[1])) {
557726947304SEvan Yan 			DEBUG0("Failed to update ranges (memory)\n");
557826947304SEvan Yan 			return (PCICFG_FAILURE);
557926947304SEvan Yan 		}
558026947304SEvan Yan 	}
558126947304SEvan Yan 
558226947304SEvan Yan 	/*
558326947304SEvan Yan 	 * Remove the resource maps for the bridge since we no longer
558426947304SEvan Yan 	 * need them.  Note that the failure is ignored since the
558526947304SEvan Yan 	 * ndi_devi_offline above may have already taken care of it via
558626947304SEvan Yan 	 * driver detach.
558726947304SEvan Yan 	 * It has been checked that there are no other reasons for
558826947304SEvan Yan 	 * failure other than map itself being non-existent. So we are Ok.
558926947304SEvan Yan 	 */
559026947304SEvan Yan 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
559126947304SEvan Yan 		/*EMPTY*/
559226947304SEvan Yan 		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n");
559326947304SEvan Yan 	}
559426947304SEvan Yan 
559526947304SEvan Yan 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
559626947304SEvan Yan 		/*EMPTY*/
559726947304SEvan Yan 		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n");
559826947304SEvan Yan 	}
559926947304SEvan Yan 
560026947304SEvan Yan 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM)
560126947304SEvan Yan 	    == NDI_FAILURE) {
560226947304SEvan Yan 		/*EMPTY*/
560326947304SEvan Yan 		DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
560426947304SEvan Yan 	}
560526947304SEvan Yan 
560626947304SEvan Yan 	return (rval);
560726947304SEvan Yan }
560826947304SEvan Yan 
560926947304SEvan Yan /*
561026947304SEvan Yan  * Return PCICFG_SUCCESS if device exists at the specified address.
561126947304SEvan Yan  * Return PCICFG_NODEVICE is no device exists at the specified address.
561226947304SEvan Yan  *
561326947304SEvan Yan  */
561426947304SEvan Yan int
561526947304SEvan Yan pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
561626947304SEvan Yan {
561726947304SEvan Yan 	caddr_t			virt;
561826947304SEvan Yan 	ddi_device_acc_attr_t	attr;
561926947304SEvan Yan 	int			status;
562026947304SEvan Yan 	int			rlen;
562126947304SEvan Yan 	pci_regspec_t		*reg;
562226947304SEvan Yan 	int			ret = DDI_SUCCESS;
562326947304SEvan Yan 	int16_t			tmp;
562426947304SEvan Yan 	/*
562526947304SEvan Yan 	 * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly
562626947304SEvan Yan 	 * mapped, otherwise it is 0. "flags" is introduced in support of any
562726947304SEvan Yan 	 * non transparent bridges, where configuration space is indirectly
562826947304SEvan Yan 	 * mapped.
562926947304SEvan Yan 	 * Indirect mapping is always true on sun4v systems.
563026947304SEvan Yan 	 */
563126947304SEvan Yan 	int			flags = 0;
563226947304SEvan Yan 
563326947304SEvan Yan 
563426947304SEvan Yan 	/*
563526947304SEvan Yan 	 * Get the pci register spec from the node
563626947304SEvan Yan 	 */
563726947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
563826947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
563926947304SEvan Yan 
564026947304SEvan Yan 	switch (status) {
564126947304SEvan Yan 		case DDI_PROP_SUCCESS:
564226947304SEvan Yan 		break;
564326947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
564426947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
564526947304SEvan Yan 			return (PCICFG_FAILURE);
564626947304SEvan Yan 		default:
564726947304SEvan Yan 			DEBUG0("no reg property\n");
564826947304SEvan Yan 			return (PCICFG_FAILURE);
564926947304SEvan Yan 	}
565026947304SEvan Yan 
565126947304SEvan Yan 	if (pcicfg_indirect_map(dip) == DDI_SUCCESS)
565226947304SEvan Yan 		flags |= PCICFG_CONF_INDIRECT_MAP;
565326947304SEvan Yan 
565426947304SEvan Yan 	/*
565526947304SEvan Yan 	 * Map in configuration space (temporarily)
565626947304SEvan Yan 	 */
565726947304SEvan Yan 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
565826947304SEvan Yan 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
565926947304SEvan Yan 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
566026947304SEvan Yan 	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
566126947304SEvan Yan 
566226947304SEvan Yan #ifdef	EFCODE21554
566326947304SEvan Yan 	if (ddi_regs_map_setup(dip, 0, &virt,
566426947304SEvan Yan 	    0, 0, &attr, handle) != DDI_SUCCESS)
566526947304SEvan Yan #else
566626947304SEvan Yan 	if (pcicfg_map_phys(dip, reg, &virt, &attr, handle)
566726947304SEvan Yan 	    != DDI_SUCCESS)
566826947304SEvan Yan #endif
566926947304SEvan Yan 	{
567026947304SEvan Yan 		DEBUG0("pcicfg_config_setup():"
567126947304SEvan Yan 		"Failed to setup config space\n");
567226947304SEvan Yan 
567326947304SEvan Yan 		kmem_free((caddr_t)reg, rlen);
567426947304SEvan Yan 		return (PCICFG_FAILURE);
567526947304SEvan Yan 	}
567626947304SEvan Yan 
567726947304SEvan Yan 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
567826947304SEvan Yan 		/*
567926947304SEvan Yan 		 * need to use DDI interfaces as the conf space is
568026947304SEvan Yan 		 * cannot be directly accessed by the host.
568126947304SEvan Yan 		 */
568226947304SEvan Yan 		tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt);
568326947304SEvan Yan 	} else {
568426947304SEvan Yan 		ret = ddi_peek16(dip, (int16_t *)virt, &tmp);
568526947304SEvan Yan 	}
568626947304SEvan Yan 
568726947304SEvan Yan 	if (ret == DDI_SUCCESS) {
568826947304SEvan Yan 		if (tmp == -1) {
568926947304SEvan Yan 			DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
569026947304SEvan Yan 			ret = PCICFG_NODEVICE;
569126947304SEvan Yan 		} else {
569226947304SEvan Yan 			/* XXX - Need to check why HV is returning 0 */
569326947304SEvan Yan 			if (tmp == 0) {
569426947304SEvan Yan 				DEBUG0("Device Not Ready yet ?");
569526947304SEvan Yan 				ret = PCICFG_NODEVICE;
569626947304SEvan Yan 			} else {
569726947304SEvan Yan 				DEBUG1("DEVICEFOUND, read %x\n", tmp);
569826947304SEvan Yan 				ret = PCICFG_SUCCESS;
569926947304SEvan Yan 			}
570026947304SEvan Yan 		}
570126947304SEvan Yan 	} else {
570226947304SEvan Yan 		DEBUG0("ddi_peek failed, must be NODEVICE\n");
570326947304SEvan Yan 		ret = PCICFG_NODEVICE;
570426947304SEvan Yan 	}
570526947304SEvan Yan 
570626947304SEvan Yan 	/*
570726947304SEvan Yan 	 * A bug in XMITS 3.0 causes us to miss the Master Abort Split
570826947304SEvan Yan 	 * Completion message.  The result is the error message being
570926947304SEvan Yan 	 * sent back as part of the config data.  If the first two words
571026947304SEvan Yan 	 * of the config space happen to be the same as the Master Abort
571126947304SEvan Yan 	 * message, then report back that there is no device there.
571226947304SEvan Yan 	 */
571326947304SEvan Yan 	if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) {
571426947304SEvan Yan 		int32_t	pcix_scm;
571526947304SEvan Yan 
571626947304SEvan Yan #define		PCICFG_PCIX_SCM	0x10000004
571726947304SEvan Yan 
571826947304SEvan Yan 		pcix_scm = 0;
571926947304SEvan Yan 		(void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm);
572026947304SEvan Yan 		if (pcix_scm == PCICFG_PCIX_SCM) {
572126947304SEvan Yan 			pcix_scm = 0;
572226947304SEvan Yan 			(void) ddi_peek32(dip,
572326947304SEvan Yan 			    (int32_t *)(virt + 4), &pcix_scm);
572426947304SEvan Yan 			if (pcix_scm == PCICFG_PCIX_SCM)
572526947304SEvan Yan 				ret = PCICFG_NODEVICE;
572626947304SEvan Yan 		}
572726947304SEvan Yan 	}
572826947304SEvan Yan 
572926947304SEvan Yan 	if (ret == PCICFG_NODEVICE)
573026947304SEvan Yan #ifdef	EFCODE21554
573126947304SEvan Yan 		ddi_regs_map_free(handle);
573226947304SEvan Yan #else
573326947304SEvan Yan 		pcicfg_unmap_phys(handle, reg);
573426947304SEvan Yan #endif
573526947304SEvan Yan 
573626947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
573726947304SEvan Yan 
573826947304SEvan Yan 	return (ret);
573926947304SEvan Yan 
574026947304SEvan Yan }
574126947304SEvan Yan 
574226947304SEvan Yan static void
574326947304SEvan Yan pcicfg_config_teardown(ddi_acc_handle_t *handle)
574426947304SEvan Yan {
574526947304SEvan Yan 	(void) ddi_regs_map_free(handle);
574626947304SEvan Yan }
574726947304SEvan Yan 
574826947304SEvan Yan static int
574926947304SEvan Yan pcicfg_add_config_reg(dev_info_t *dip,
575026947304SEvan Yan 	uint_t bus, uint_t device, uint_t func)
575126947304SEvan Yan {
575226947304SEvan Yan 	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
575326947304SEvan Yan 
575426947304SEvan Yan 	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
575526947304SEvan Yan 
575626947304SEvan Yan 	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
575726947304SEvan Yan 	    "reg", reg, 5));
575826947304SEvan Yan }
575926947304SEvan Yan 
576026947304SEvan Yan static int
576126947304SEvan Yan pcicfg_dump_assigned(dev_info_t *dip)
576226947304SEvan Yan {
576326947304SEvan Yan 	pci_regspec_t		*reg;
576426947304SEvan Yan 	int			length;
576526947304SEvan Yan 	int			rcount;
576626947304SEvan Yan 	int			i;
576726947304SEvan Yan 
576826947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
576926947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&reg,
577026947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
577126947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
577226947304SEvan Yan 		return (PCICFG_FAILURE);
577326947304SEvan Yan 	}
577426947304SEvan Yan 
577526947304SEvan Yan 	rcount = length / sizeof (pci_regspec_t);
577626947304SEvan Yan 	for (i = 0; i < rcount; i++) {
577726947304SEvan Yan 		DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n",
577826947304SEvan Yan 		    reg[i].pci_size_low, reg[i].pci_phys_low,
577926947304SEvan Yan 		    reg[i].pci_phys_mid, reg[i].pci_phys_hi);
578026947304SEvan Yan 	}
578126947304SEvan Yan 	/*
578226947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
578326947304SEvan Yan 	 */
578426947304SEvan Yan 	kmem_free((caddr_t)reg, length);
578526947304SEvan Yan 
578626947304SEvan Yan 	return (PCICFG_SUCCESS);
578726947304SEvan Yan }
578826947304SEvan Yan 
578926947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE
579026947304SEvan Yan static int
579126947304SEvan Yan pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func,
579226947304SEvan Yan     uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr,
579326947304SEvan Yan     int *fcode_size, int rom_paddr, int rom_size)
579426947304SEvan Yan {
579526947304SEvan Yan 	pci_regspec_t		p;
579626947304SEvan Yan 	int			pci_data;
579726947304SEvan Yan 	int			start_of_fcode;
579826947304SEvan Yan 	int			image_length;
579926947304SEvan Yan 	int			code_type;
580026947304SEvan Yan 	ddi_acc_handle_t	h;
580126947304SEvan Yan 	ddi_device_acc_attr_t	acc;
580226947304SEvan Yan 	uint8_t			*addr;
580326947304SEvan Yan 	int8_t			image_not_found, indicator;
580426947304SEvan Yan 	uint16_t		vendor_id_img, device_id_img;
580526947304SEvan Yan 	int16_t			rom_sig;
580626947304SEvan Yan #ifdef DEBUG
580726947304SEvan Yan 	int i;
580826947304SEvan Yan #endif
580926947304SEvan Yan 
581026947304SEvan Yan 	DEBUG4("pcicfg_load_fcode() - "
581126947304SEvan Yan 	    "bus %x device =%x func=%x rom_paddr=%lx\n",
581226947304SEvan Yan 	    bus, device, func, rom_paddr);
581326947304SEvan Yan 	DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n",
581426947304SEvan Yan 	    vendor_id, device_id);
581526947304SEvan Yan 
581626947304SEvan Yan 	*fcode_size = 0;
581726947304SEvan Yan 	*fcode_addr = NULL;
581826947304SEvan Yan 
581926947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
582026947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
582126947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
582226947304SEvan Yan 
582326947304SEvan Yan 	p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device,
582426947304SEvan Yan 	    func, PCI_CONF_ROM);
582526947304SEvan Yan 
582626947304SEvan Yan 	p.pci_phys_mid = 0;
582726947304SEvan Yan 	p.pci_phys_low = 0;
582826947304SEvan Yan 
582926947304SEvan Yan 	p.pci_size_low = rom_size;
583026947304SEvan Yan 	p.pci_size_hi = 0;
583126947304SEvan Yan 
583226947304SEvan Yan 	if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) {
583326947304SEvan Yan 		DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low);
583426947304SEvan Yan 		return (PCICFG_FAILURE);
583526947304SEvan Yan 	}
583626947304SEvan Yan 
583726947304SEvan Yan 	/*
583826947304SEvan Yan 	 * Walk the ROM to find the proper image for this device.
583926947304SEvan Yan 	 */
584026947304SEvan Yan 	image_not_found = 1;
584126947304SEvan Yan 	while (image_not_found) {
584226947304SEvan Yan 		DEBUG1("Expansion ROM maps to %lx\n", addr);
584326947304SEvan Yan 
584426947304SEvan Yan #ifdef DEBUG
584526947304SEvan Yan 		if (pcicfg_dump_fcode) {
584626947304SEvan Yan 			for (i = 0; i < 100; i++)
584726947304SEvan Yan 				DEBUG2("ROM 0x%x --> 0x%x\n", i,
584826947304SEvan Yan 				    ddi_get8(h, (uint8_t *)(addr + i)));
584926947304SEvan Yan 		}
585026947304SEvan Yan #endif
585126947304SEvan Yan 
585226947304SEvan Yan 		/*
585326947304SEvan Yan 		 * Some device say they have an Expansion ROM, but do not, so
585426947304SEvan Yan 		 * for non-21554 devices use peek so we don't panic due to
585526947304SEvan Yan 		 * accessing non existent memory.
585626947304SEvan Yan 		 */
585726947304SEvan Yan 		if (pcicfg_indirect_map(dip) == DDI_SUCCESS) {
585826947304SEvan Yan 			rom_sig = ddi_get16(h,
585926947304SEvan Yan 			    (uint16_t *)(addr + PCI_ROM_SIGNATURE));
586026947304SEvan Yan 		} else {
586126947304SEvan Yan 			if (ddi_peek16(dip,
586226947304SEvan Yan 			    (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) {
586326947304SEvan Yan 				cmn_err(CE_WARN,
586426947304SEvan Yan 				    "PCI Expansion ROM is not accessible");
586526947304SEvan Yan 				pcicfg_unmap_phys(&h, &p);
586626947304SEvan Yan 				return (PCICFG_FAILURE);
586726947304SEvan Yan 			}
586826947304SEvan Yan 		}
586926947304SEvan Yan 
587026947304SEvan Yan 		/*
587126947304SEvan Yan 		 * Validate the ROM Signature.
587226947304SEvan Yan 		 */
587326947304SEvan Yan 		if ((uint16_t)rom_sig != 0xaa55) {
587426947304SEvan Yan 			DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig);
587526947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
587626947304SEvan Yan 			return (PCICFG_FAILURE);
587726947304SEvan Yan 		}
587826947304SEvan Yan 
587926947304SEvan Yan 		DEBUG0("Valid ROM Signature Found\n");
588026947304SEvan Yan 
588126947304SEvan Yan 		start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2));
588226947304SEvan Yan 
588326947304SEvan Yan 		pci_data =  ddi_get16(h,
588426947304SEvan Yan 		    (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR));
588526947304SEvan Yan 
588626947304SEvan Yan 		DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data,
588726947304SEvan Yan 		    addr);
588826947304SEvan Yan 
588926947304SEvan Yan 		/*
589026947304SEvan Yan 		 * Validate the PCI Data Structure Signature.
589126947304SEvan Yan 		 * 0x52494350 = "PCIR"
589226947304SEvan Yan 		 */
589326947304SEvan Yan 
589426947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) {
589526947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
589626947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
589726947304SEvan Yan 			return (PCICFG_FAILURE);
589826947304SEvan Yan 		}
589926947304SEvan Yan 
590026947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) {
590126947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
590226947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
590326947304SEvan Yan 			return (PCICFG_FAILURE);
590426947304SEvan Yan 		}
590526947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) {
590626947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
590726947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
590826947304SEvan Yan 			return (PCICFG_FAILURE);
590926947304SEvan Yan 		}
591026947304SEvan Yan 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) {
591126947304SEvan Yan 			DEBUG0("Invalid PCI Data Structure Signature\n");
591226947304SEvan Yan 			pcicfg_unmap_phys(&h, &p);
591326947304SEvan Yan 			return (PCICFG_FAILURE);
591426947304SEvan Yan 		}
591526947304SEvan Yan 
591626947304SEvan Yan 		/*
591726947304SEvan Yan 		 * Is this image for this device?
591826947304SEvan Yan 		 */
591926947304SEvan Yan 		vendor_id_img = ddi_get16(h,
592026947304SEvan Yan 		    (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID));
592126947304SEvan Yan 		device_id_img = ddi_get16(h,
592226947304SEvan Yan 		    (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID));
592326947304SEvan Yan 
592426947304SEvan Yan 		DEBUG2("This image is for vendor_id=%x device_id=%x\n",
592526947304SEvan Yan 		    vendor_id_img, device_id_img);
592626947304SEvan Yan 
592726947304SEvan Yan 		code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE);
592826947304SEvan Yan 
592926947304SEvan Yan 		switch (code_type) {
593026947304SEvan Yan 		case PCI_PDS_CODE_TYPE_PCAT:
593126947304SEvan Yan 			DEBUG0("ROM is of x86/PC-AT Type\n");
593226947304SEvan Yan 			break;
593326947304SEvan Yan 		case PCI_PDS_CODE_TYPE_OPEN_FW:
593426947304SEvan Yan 			DEBUG0("ROM is of Open Firmware Type\n");
593526947304SEvan Yan 			break;
593626947304SEvan Yan 		default:
593726947304SEvan Yan 			DEBUG1("ROM is of Unknown Type 0x%x\n", code_type);
593826947304SEvan Yan 			break;
593926947304SEvan Yan 		}
594026947304SEvan Yan 
594126947304SEvan Yan 		if ((vendor_id_img != vendor_id) ||
594226947304SEvan Yan 		    (device_id_img != device_id) ||
594326947304SEvan Yan 		    (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) {
594426947304SEvan Yan 			DEBUG0("Firmware Image is not for this device..."
594526947304SEvan Yan 			    "goto next image\n");
594626947304SEvan Yan 			/*
594726947304SEvan Yan 			 * Read indicator byte to see if there is another
594826947304SEvan Yan 			 * image in the ROM
594926947304SEvan Yan 			 */
595026947304SEvan Yan 			indicator = ddi_get8(h,
595126947304SEvan Yan 			    (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR));
595226947304SEvan Yan 
595326947304SEvan Yan 			if (indicator != 1) {
595426947304SEvan Yan 				/*
595526947304SEvan Yan 				 * There is another image in the ROM.
595626947304SEvan Yan 				 */
595726947304SEvan Yan 				image_length = ddi_get16(h,  (uint16_t *)(addr +
595826947304SEvan Yan 				    pci_data + PCI_PDS_IMAGE_LENGTH)) * 512;
595926947304SEvan Yan 
596026947304SEvan Yan 				addr += image_length;
596126947304SEvan Yan 			} else {
596226947304SEvan Yan 				/*
596326947304SEvan Yan 				 * There are no more images.
596426947304SEvan Yan 				 */
596526947304SEvan Yan 				DEBUG0("There are no more images in the ROM\n");
596626947304SEvan Yan 				pcicfg_unmap_phys(&h, &p);
596726947304SEvan Yan 
596826947304SEvan Yan 				return (PCICFG_FAILURE);
596926947304SEvan Yan 			}
597026947304SEvan Yan 		} else {
597126947304SEvan Yan 			DEBUG0("Correct image was found\n");
597226947304SEvan Yan 			image_not_found = 0;  /* Image was found */
597326947304SEvan Yan 		}
597426947304SEvan Yan 	}
597526947304SEvan Yan 
597626947304SEvan Yan 	*fcode_size =  (ddi_get8(h, addr + start_of_fcode + 4) << 24) |
597726947304SEvan Yan 	    (ddi_get8(h, addr + start_of_fcode + 5) << 16) |
597826947304SEvan Yan 	    (ddi_get8(h, addr + start_of_fcode + 6) << 8) |
597926947304SEvan Yan 	    (ddi_get8(h, addr + start_of_fcode + 7));
598026947304SEvan Yan 
598126947304SEvan Yan 	DEBUG1("Fcode Size %x\n", *fcode_size);
598226947304SEvan Yan 
598326947304SEvan Yan 	/*
598426947304SEvan Yan 	 * Allocate page aligned buffer space
598526947304SEvan Yan 	 */
598626947304SEvan Yan 	*fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP);
598726947304SEvan Yan 
598826947304SEvan Yan 	if (*fcode_addr == NULL) {
598926947304SEvan Yan 		DEBUG0("kmem_zalloc returned NULL\n");
599026947304SEvan Yan 		pcicfg_unmap_phys(&h, &p);
599126947304SEvan Yan 		return (PCICFG_FAILURE);
599226947304SEvan Yan 	}
599326947304SEvan Yan 
599426947304SEvan Yan 	DEBUG1("Fcode Addr %lx\n", *fcode_addr);
599526947304SEvan Yan 
599626947304SEvan Yan 	ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size,
599726947304SEvan Yan 	    DDI_DEV_AUTOINCR);
599826947304SEvan Yan 
599926947304SEvan Yan 	pcicfg_unmap_phys(&h, &p);
600026947304SEvan Yan 
600126947304SEvan Yan 	return (PCICFG_SUCCESS);
600226947304SEvan Yan }
600326947304SEvan Yan 
600426947304SEvan Yan static int
600526947304SEvan Yan pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus,
600626947304SEvan Yan     uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec)
600726947304SEvan Yan {
600826947304SEvan Yan 	/*
600926947304SEvan Yan 	 * Assign values to all BARs so that it is safe to turn on the
601026947304SEvan Yan 	 * device for accessing the fcode on the PROM. On successful
601126947304SEvan Yan 	 * exit from this function, "assigned-addresses" are created
601226947304SEvan Yan 	 * for all BARs and ROM BAR is enabled. Also, rom_regspec is
601326947304SEvan Yan 	 * filled with the values that can be used to free up this
601426947304SEvan Yan 	 * resource later.
601526947304SEvan Yan 	 */
601626947304SEvan Yan 	uint32_t request, hiword, size;
601726947304SEvan Yan 	pci_regspec_t phys_spec;
601826947304SEvan Yan 	ndi_ra_request_t req;
601926947304SEvan Yan 	uint64_t mem_answer, mem_alen;
602026947304SEvan Yan 	int i;
602126947304SEvan Yan 
602226947304SEvan Yan 	DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name);
602326947304SEvan Yan 
602426947304SEvan Yan 	/*
602526947304SEvan Yan 	 * Process the BARs.
602626947304SEvan Yan 	 */
602726947304SEvan Yan 	for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) {
602826947304SEvan Yan 		pci_config_put32(h, i, 0xffffffff);
602926947304SEvan Yan 		request = pci_config_get32(h, i);
603026947304SEvan Yan 		/*
603126947304SEvan Yan 		 * Check if implemented
603226947304SEvan Yan 		 */
603326947304SEvan Yan 		if (request == 0) {
603426947304SEvan Yan 			DEBUG1("pcicfg_fcode_assign_bars :"
603526947304SEvan Yan 			    "BASE register [0x%x] asks for 0(32)\n", i);
603626947304SEvan Yan 			i += 4;
603726947304SEvan Yan 			continue;
603826947304SEvan Yan 		}
603926947304SEvan Yan 		/*
604026947304SEvan Yan 		 * Build the phys_spec for this BAR
604126947304SEvan Yan 		 */
604226947304SEvan Yan 		hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i);
604326947304SEvan Yan 		size = (~(PCI_BASE_M_ADDR_M & request)) + 1;
604426947304SEvan Yan 
604526947304SEvan Yan 		DEBUG3("pcicfg_fcode_assign_bars :"
604626947304SEvan Yan 		    "BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
604726947304SEvan Yan 		    i, request, size);
604826947304SEvan Yan 
604926947304SEvan Yan 		if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) {
605026947304SEvan Yan 			if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) {
605126947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
605226947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & request)
605326947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
605426947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
605526947304SEvan Yan 			}
605626947304SEvan Yan 			if (request & PCI_BASE_PREF_M)
605726947304SEvan Yan 				hiword |= PCI_REG_PF_M;
605826947304SEvan Yan 		} else {
605926947304SEvan Yan 			hiword |= PCI_ADDR_IO;
606026947304SEvan Yan 		}
606126947304SEvan Yan 		phys_spec.pci_phys_hi = hiword;
606226947304SEvan Yan 		phys_spec.pci_phys_mid = 0;
606326947304SEvan Yan 		phys_spec.pci_phys_low = 0;
606426947304SEvan Yan 		phys_spec.pci_size_hi = 0;
606526947304SEvan Yan 		phys_spec.pci_size_low = size;
606626947304SEvan Yan 
606726947304SEvan Yan 		/*
606826947304SEvan Yan 		 * The following function
606926947304SEvan Yan 		 * - allocates address space
607026947304SEvan Yan 		 * - programs the BAR
607126947304SEvan Yan 		 * - adds an "assigned-addresses" property
607226947304SEvan Yan 		 */
607326947304SEvan Yan 		if (pcicfg_alloc_resource(dip, phys_spec)) {
607426947304SEvan Yan 			cmn_err(CE_WARN, "failed to allocate %d bytes"
607526947304SEvan Yan 			    " for dev %s BASE register [0x%x]\n",
607626947304SEvan Yan 			    size, DEVI(dip)->devi_name, i);
607726947304SEvan Yan 			goto failure;
607826947304SEvan Yan 		}
607926947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
608026947304SEvan Yan 			/*
608126947304SEvan Yan 			 * 64 bit, should be in memory space.
608226947304SEvan Yan 			 */
608326947304SEvan Yan 			i += 8;
608426947304SEvan Yan 		} else {
608526947304SEvan Yan 			/*
608626947304SEvan Yan 			 * 32 bit, either memory or I/O space.
608726947304SEvan Yan 			 */
608826947304SEvan Yan 			i += 4;
608926947304SEvan Yan 		}
609026947304SEvan Yan 	}
609126947304SEvan Yan 
609226947304SEvan Yan 	/*
609326947304SEvan Yan 	 * Handle ROM BAR. We do not use the common
609426947304SEvan Yan 	 * resource allocator function because we need to
609526947304SEvan Yan 	 * return reg spec to the caller.
609626947304SEvan Yan 	 */
609726947304SEvan Yan 	size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1;
609826947304SEvan Yan 
609926947304SEvan Yan 	DEBUG3("BASE register [0x%x] asks for "
610026947304SEvan Yan 	    "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size);
610126947304SEvan Yan 
610226947304SEvan Yan 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
610326947304SEvan Yan 
610426947304SEvan Yan 	req.ra_boundbase = 0;
610526947304SEvan Yan 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
610626947304SEvan Yan 	req.ra_len = size;
610726947304SEvan Yan 	req.ra_flags |= NDI_RA_ALIGN_SIZE;
610826947304SEvan Yan 	req.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
610926947304SEvan Yan 
611026947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(dip),
611126947304SEvan Yan 	    &req, &mem_answer, &mem_alen,
611226947304SEvan Yan 	    NDI_RA_TYPE_MEM, NDI_RA_PASS)) {
611326947304SEvan Yan 		cmn_err(CE_WARN, "failed to allocate %d bytes"
611426947304SEvan Yan 		    " for dev %s ROM BASE register\n",
611526947304SEvan Yan 		    size, DEVI(dip)->devi_name);
611626947304SEvan Yan 		goto failure;
611726947304SEvan Yan 	}
611826947304SEvan Yan 
611926947304SEvan Yan 	DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
612026947304SEvan Yan 	    PCICFG_HIADDR(mem_answer),
612126947304SEvan Yan 	    PCICFG_LOADDR(mem_answer), mem_alen);
612226947304SEvan Yan 
612326947304SEvan Yan 	/*
612426947304SEvan Yan 	 * Assign address space and enable ROM.
612526947304SEvan Yan 	 */
612626947304SEvan Yan 	pci_config_put32(h, PCI_CONF_ROM,
612726947304SEvan Yan 	    PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE);
612826947304SEvan Yan 
612926947304SEvan Yan 	/*
613026947304SEvan Yan 	 * Add resource to assigned-addresses.
613126947304SEvan Yan 	 */
613226947304SEvan Yan 	phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \
613326947304SEvan Yan 	    PCI_CONF_ROM) | PCI_ADDR_MEM32;
613426947304SEvan Yan 	if (fc_request & PCI_BASE_PREF_M)
613526947304SEvan Yan 		phys_spec.pci_phys_hi |= PCI_REG_PF_M;
613626947304SEvan Yan 	phys_spec.pci_phys_mid = 0;
613726947304SEvan Yan 	phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer);
613826947304SEvan Yan 	phys_spec.pci_size_hi = 0;
613926947304SEvan Yan 	phys_spec.pci_size_low = size;
614026947304SEvan Yan 
614126947304SEvan Yan 	if (pcicfg_update_assigned_prop(dip, &phys_spec)
614226947304SEvan Yan 	    != PCICFG_SUCCESS) {
614326947304SEvan Yan 		cmn_err(CE_WARN, "failed to update"
614426947304SEvan Yan 		    " assigned-address property for dev %s\n",
614526947304SEvan Yan 		    DEVI(dip)->devi_name);
614626947304SEvan Yan 		goto failure;
614726947304SEvan Yan 	}
614826947304SEvan Yan 	/*
614926947304SEvan Yan 	 * Copy out the reg spec.
615026947304SEvan Yan 	 */
615126947304SEvan Yan 	*rom_regspec = phys_spec;
615226947304SEvan Yan 
615326947304SEvan Yan 	return (PCICFG_SUCCESS);
615426947304SEvan Yan 
615526947304SEvan Yan failure:
615626947304SEvan Yan 	/*
615726947304SEvan Yan 	 * We came in with no "assigned-addresses".
615826947304SEvan Yan 	 * Free up the resources we may have allocated.
615926947304SEvan Yan 	 */
616026947304SEvan Yan 	(void) pcicfg_free_device_resources(dip, 0);
616126947304SEvan Yan 
616226947304SEvan Yan 	return (PCICFG_FAILURE);
616326947304SEvan Yan }
616426947304SEvan Yan 
616526947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */
616626947304SEvan Yan 
616726947304SEvan Yan static int
616826947304SEvan Yan pcicfg_free_all_resources(dev_info_t *dip)
616926947304SEvan Yan {
617026947304SEvan Yan 	pci_regspec_t		*assigned;
617126947304SEvan Yan 	int			assigned_len;
617226947304SEvan Yan 	int			acount;
617326947304SEvan Yan 	int			i;
617426947304SEvan Yan 
617526947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
617626947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
617726947304SEvan Yan 	    &assigned_len) != DDI_PROP_SUCCESS) {
617826947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
617926947304SEvan Yan 		return (PCICFG_FAILURE);
618026947304SEvan Yan 	}
618126947304SEvan Yan 
618226947304SEvan Yan 	acount = assigned_len / sizeof (pci_regspec_t);
618326947304SEvan Yan 
618426947304SEvan Yan 	for (i = 0; i < acount; i++) {
618526947304SEvan Yan 		if (pcicfg_free_resource(dip, assigned[i], 0)) {
618626947304SEvan Yan 			/*
618726947304SEvan Yan 			 * Dont forget to free mem from ddi_getlongprop
618826947304SEvan Yan 			 */
618926947304SEvan Yan 			kmem_free((caddr_t)assigned, assigned_len);
619026947304SEvan Yan 			return (PCICFG_FAILURE);
619126947304SEvan Yan 		}
619226947304SEvan Yan 	}
619326947304SEvan Yan 
619426947304SEvan Yan 	/*
619526947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
619626947304SEvan Yan 	 */
619726947304SEvan Yan 	if (assigned_len)
619826947304SEvan Yan 		kmem_free((caddr_t)assigned, assigned_len);
619926947304SEvan Yan 
620026947304SEvan Yan 	return (PCICFG_SUCCESS);
620126947304SEvan Yan }
620226947304SEvan Yan static int
620326947304SEvan Yan pcicfg_alloc_new_resources(dev_info_t *dip)
620426947304SEvan Yan {
620526947304SEvan Yan 	pci_regspec_t		*assigned, *reg;
620626947304SEvan Yan 	int			assigned_len, reg_len;
620726947304SEvan Yan 	int			acount, rcount;
620826947304SEvan Yan 	int			i, j, alloc_size;
620926947304SEvan Yan 	boolean_t		alloc;
621026947304SEvan Yan 
621126947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
621226947304SEvan Yan 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
621326947304SEvan Yan 	    &reg_len) != DDI_PROP_SUCCESS) {
621426947304SEvan Yan 		DEBUG0("Failed to read reg property\n");
621526947304SEvan Yan 		return (PCICFG_FAILURE);
621626947304SEvan Yan 	}
621726947304SEvan Yan 	rcount = reg_len / sizeof (pci_regspec_t);
621826947304SEvan Yan 
621926947304SEvan Yan 	DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n",
622026947304SEvan Yan 	    reg_len, rcount);
622126947304SEvan Yan 
622226947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
622326947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
622426947304SEvan Yan 	    &assigned_len) != DDI_PROP_SUCCESS) {
622526947304SEvan Yan 		acount = 0;
622626947304SEvan Yan 	} else {
622726947304SEvan Yan 		acount = assigned_len / sizeof (pci_regspec_t);
622826947304SEvan Yan 	}
622926947304SEvan Yan 
623026947304SEvan Yan 	DEBUG1("assigned-addresses property len=%x\n", acount);
623126947304SEvan Yan 
623226947304SEvan Yan 	/*
623326947304SEvan Yan 	 * For each address described by reg, search for it in the
623426947304SEvan Yan 	 * assigned-addresses property. If it does not exist, allocate
623526947304SEvan Yan 	 * resources for it. If it does exist, check the size in both.
623626947304SEvan Yan 	 * The size needs to be bigger of the two.
623726947304SEvan Yan 	 */
623826947304SEvan Yan 	for (i = 1; i < rcount; i++) {
623926947304SEvan Yan 		alloc = B_TRUE;
624026947304SEvan Yan 		alloc_size = reg[i].pci_size_low;
624126947304SEvan Yan 		for (j = 0; j < acount; j++) {
624226947304SEvan Yan 			if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) {
624326947304SEvan Yan 				/*
624426947304SEvan Yan 				 * There is an exact match. Check size.
624526947304SEvan Yan 				 */
624626947304SEvan Yan 				DEBUG1("pcicfg_alloc_new_resources "
624726947304SEvan Yan 				    "- %x - MATCH\n",
624826947304SEvan Yan 				    reg[i].pci_phys_hi);
624926947304SEvan Yan 
625026947304SEvan Yan 				if (reg[i].pci_size_low >
625126947304SEvan Yan 				    assigned[j].pci_size_low) {
625226947304SEvan Yan 					/*
625326947304SEvan Yan 					 * Fcode wants more.
625426947304SEvan Yan 					 */
625526947304SEvan Yan 					DEBUG3("pcicfg_alloc_new_resources"
625626947304SEvan Yan 					    " - %x - RESIZE"
625726947304SEvan Yan 					    " assigned 0x%x reg 0x%x\n",
625826947304SEvan Yan 					    assigned[j].pci_phys_hi,
625926947304SEvan Yan 					    assigned[j].pci_size_low,
626026947304SEvan Yan 					    reg[i].pci_size_low);
626126947304SEvan Yan 
626226947304SEvan Yan 					/*
626326947304SEvan Yan 					 * Free the old resource.
626426947304SEvan Yan 					 */
626526947304SEvan Yan 					(void) pcicfg_free_resource(dip,
626626947304SEvan Yan 					    assigned[j], 0);
626726947304SEvan Yan 				} else {
626826947304SEvan Yan 					DEBUG3("pcicfg_alloc_new_resources"
626926947304SEvan Yan 					    " - %x - ENOUGH"
627026947304SEvan Yan 					    " assigned 0x%x reg 0x%x\n",
627126947304SEvan Yan 					    assigned[j].pci_phys_hi,
627226947304SEvan Yan 					    assigned[j].pci_size_low,
627326947304SEvan Yan 					    reg[i].pci_size_low);
627426947304SEvan Yan 
627526947304SEvan Yan 					alloc = B_FALSE;
627626947304SEvan Yan 				}
627726947304SEvan Yan 				break;
627826947304SEvan Yan 			}
627926947304SEvan Yan 			/*
628026947304SEvan Yan 			 * Fcode may have set one or more of the
628126947304SEvan Yan 			 * NPT bits in phys.hi.
628226947304SEvan Yan 			 */
628326947304SEvan Yan 			if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) ==
628426947304SEvan Yan 			    PCI_REG_BDFR_G(reg[i].pci_phys_hi)) {
628526947304SEvan Yan 
628626947304SEvan Yan 				DEBUG2("pcicfg_alloc_new_resources "
628726947304SEvan Yan 				    "- PARTIAL MATCH assigned 0x%x "
628826947304SEvan Yan 				    "reg 0x%x\n", assigned[j].pci_phys_hi,
628926947304SEvan Yan 				    reg[i].pci_phys_hi);
629026947304SEvan Yan 				/*
629126947304SEvan Yan 				 * Changing the SS bits is an error
629226947304SEvan Yan 				 */
629326947304SEvan Yan 				if (PCI_REG_ADDR_G(
629426947304SEvan Yan 				    assigned[j].pci_phys_hi) !=
629526947304SEvan Yan 				    PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
629626947304SEvan Yan 
629726947304SEvan Yan 					DEBUG2("Fcode changing"
629826947304SEvan Yan 					    " SS bits of - 0x%x -"
629926947304SEvan Yan 					    " on %s\n", reg[i].pci_phys_hi,
630026947304SEvan Yan 					    DEVI(dip)->devi_name);
630126947304SEvan Yan 
630226947304SEvan Yan 				}
630326947304SEvan Yan 
630426947304SEvan Yan 
630526947304SEvan Yan 				/*
630626947304SEvan Yan 				 * We are going to allocate new resource.
630726947304SEvan Yan 				 * Free the old resource. Again, adjust
630826947304SEvan Yan 				 * the size to be safe.
630926947304SEvan Yan 				 */
631026947304SEvan Yan 				(void) pcicfg_free_resource(dip,
631126947304SEvan Yan 				    assigned[j], 0);
631226947304SEvan Yan 
631326947304SEvan Yan 				alloc_size = MAX(reg[i].pci_size_low,
631426947304SEvan Yan 				    assigned[j].pci_size_low);
631526947304SEvan Yan 
631626947304SEvan Yan 				break;
631726947304SEvan Yan 			}
631826947304SEvan Yan 		}
631926947304SEvan Yan 		/*
632026947304SEvan Yan 		 * We are allocating resources for one of three reasons -
632126947304SEvan Yan 		 * - Fcode wants a larger address space
632226947304SEvan Yan 		 * - Fcode has set changed/set n, p, t bits.
632326947304SEvan Yan 		 * - It is a new "reg", it should be only ROM bar, but
632426947304SEvan Yan 		 *   we don't do the checking.
632526947304SEvan Yan 		 */
632626947304SEvan Yan 		if (alloc == B_TRUE) {
632726947304SEvan Yan 			DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n",
632826947304SEvan Yan 			    reg[i].pci_phys_hi);
632926947304SEvan Yan 
633026947304SEvan Yan 			reg[i].pci_size_low = alloc_size;
633126947304SEvan Yan 			if (pcicfg_alloc_resource(dip, reg[i])) {
633226947304SEvan Yan 				/*
633326947304SEvan Yan 				 * Dont forget to free mem from
633426947304SEvan Yan 				 * ddi_getlongprop
633526947304SEvan Yan 				 */
633626947304SEvan Yan 				if (acount != 0)
633726947304SEvan Yan 					kmem_free((caddr_t)assigned,
633826947304SEvan Yan 					    assigned_len);
633926947304SEvan Yan 				kmem_free((caddr_t)reg, reg_len);
634026947304SEvan Yan 				return (PCICFG_FAILURE);
634126947304SEvan Yan 			}
634226947304SEvan Yan 		}
634326947304SEvan Yan 	}
634426947304SEvan Yan 
634526947304SEvan Yan 	/*
634626947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
634726947304SEvan Yan 	 */
634826947304SEvan Yan 	if (acount != 0)
634926947304SEvan Yan 		kmem_free((caddr_t)assigned, assigned_len);
635026947304SEvan Yan 	kmem_free((caddr_t)reg, reg_len);
635126947304SEvan Yan 
635226947304SEvan Yan 	return (PCICFG_SUCCESS);
635326947304SEvan Yan }
635426947304SEvan Yan 
635526947304SEvan Yan static int
635626947304SEvan Yan pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
635726947304SEvan Yan {
635826947304SEvan Yan 	uint64_t answer;
635926947304SEvan Yan 	uint64_t alen;
636026947304SEvan Yan 	int offset;
636126947304SEvan Yan 	pci_regspec_t config;
636226947304SEvan Yan 	caddr_t virt, v;
636326947304SEvan Yan 	ddi_device_acc_attr_t acc;
636426947304SEvan Yan 	ddi_acc_handle_t h;
636526947304SEvan Yan 	ndi_ra_request_t request;
636626947304SEvan Yan 	pci_regspec_t *assigned;
636726947304SEvan Yan 	int assigned_len, entries, i;
636826947304SEvan Yan 
636926947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
637026947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
637126947304SEvan Yan 	    &assigned_len) == DDI_PROP_SUCCESS) {
637226947304SEvan Yan 		DEBUG0("pcicfg_alloc_resource - "
637326947304SEvan Yan 		    "searching assigned-addresses\n");
637426947304SEvan Yan 
637526947304SEvan Yan 		entries = assigned_len / (sizeof (pci_regspec_t));
637626947304SEvan Yan 
637726947304SEvan Yan 		/*
637826947304SEvan Yan 		 * Walk through the assigned-addresses entries. If there is
637926947304SEvan Yan 		 * a match, there is no need to allocate the resource.
638026947304SEvan Yan 		 */
638126947304SEvan Yan 		for (i = 0; i < entries; i++) {
638226947304SEvan Yan 			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
638326947304SEvan Yan 				DEBUG1("pcicfg_alloc_resource - MATCH %x\n",
638426947304SEvan Yan 				    assigned[i].pci_phys_hi);
638526947304SEvan Yan 				kmem_free(assigned, assigned_len);
638626947304SEvan Yan 				return (0);
638726947304SEvan Yan 			}
638826947304SEvan Yan 		}
638926947304SEvan Yan 		kmem_free(assigned, assigned_len);
639026947304SEvan Yan 	}
639126947304SEvan Yan 
639226947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
639326947304SEvan Yan 
639426947304SEvan Yan 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
639526947304SEvan Yan 	config.pci_phys_hi &= ~PCI_REG_REG_M;
639626947304SEvan Yan 	config.pci_phys_mid = config.pci_phys_low = 0;
639726947304SEvan Yan 	config.pci_size_hi = config.pci_size_low = 0;
639826947304SEvan Yan 
639926947304SEvan Yan 	/*
640026947304SEvan Yan 	 * Map in configuration space (temporarily)
640126947304SEvan Yan 	 */
640226947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
640326947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
640426947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
640526947304SEvan Yan 
640626947304SEvan Yan 	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
640726947304SEvan Yan 		DEBUG0("Can not map in config space\n");
640826947304SEvan Yan 		return (1);
640926947304SEvan Yan 	}
641026947304SEvan Yan 
641126947304SEvan Yan 	request.ra_flags |= NDI_RA_ALIGN_SIZE;
641226947304SEvan Yan 	request.ra_boundbase = 0;
641326947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
641426947304SEvan Yan 	/*
641526947304SEvan Yan 	 * Use size stored in phys_spec parameter.
641626947304SEvan Yan 	 */
641726947304SEvan Yan 	request.ra_len = phys_spec.pci_size_low;
641826947304SEvan Yan 
641926947304SEvan Yan 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
642026947304SEvan Yan 
642126947304SEvan Yan 	v = virt + offset;
642226947304SEvan Yan 
642326947304SEvan Yan 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
642426947304SEvan Yan 
642526947304SEvan Yan 		request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
642626947304SEvan Yan 
642726947304SEvan Yan 		/* allocate memory space from the allocator */
642826947304SEvan Yan 
642926947304SEvan Yan 		if (ndi_ra_alloc(ddi_get_parent(dip),
643026947304SEvan Yan 		    &request, &answer, &alen,
643126947304SEvan Yan 		    NDI_RA_TYPE_MEM, NDI_RA_PASS)
643226947304SEvan Yan 		    != NDI_SUCCESS) {
643326947304SEvan Yan 			DEBUG0("(ROM)Failed to allocate 32b mem");
643426947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
643526947304SEvan Yan 			return (1);
643626947304SEvan Yan 		}
643726947304SEvan Yan 		DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
643826947304SEvan Yan 		    PCICFG_HIADDR(answer),
643926947304SEvan Yan 		    PCICFG_LOADDR(answer),
644026947304SEvan Yan 		    alen);
644126947304SEvan Yan 
644226947304SEvan Yan 		/* program the low word */
644326947304SEvan Yan 
644426947304SEvan Yan 		ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer));
644526947304SEvan Yan 
644626947304SEvan Yan 		phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
644726947304SEvan Yan 		phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
644826947304SEvan Yan 	} else {
644926947304SEvan Yan 
645026947304SEvan Yan 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
645126947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
645226947304SEvan Yan 			request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
645326947304SEvan Yan 			/* allocate memory space from the allocator */
645426947304SEvan Yan 			if (ndi_ra_alloc(ddi_get_parent(dip),
645526947304SEvan Yan 			    &request, &answer, &alen,
645626947304SEvan Yan 			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
645726947304SEvan Yan 			    != NDI_SUCCESS) {
645826947304SEvan Yan 				DEBUG0("Failed to allocate 64b mem\n");
645926947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
646026947304SEvan Yan 				return (1);
646126947304SEvan Yan 			}
646226947304SEvan Yan 			DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
646326947304SEvan Yan 			    PCICFG_HIADDR(answer),
646426947304SEvan Yan 			    PCICFG_LOADDR(answer),
646526947304SEvan Yan 			    alen);
646626947304SEvan Yan 
646726947304SEvan Yan 			/* program the low word */
646826947304SEvan Yan 
646926947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
647026947304SEvan Yan 			    (uint32_t)PCICFG_LOADDR(answer));
647126947304SEvan Yan 
647226947304SEvan Yan 			/* program the high word with value zero */
647326947304SEvan Yan 			v += 4;
647426947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
647526947304SEvan Yan 			    (uint32_t)PCICFG_HIADDR(answer));
647626947304SEvan Yan 
647726947304SEvan Yan 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
647826947304SEvan Yan 			phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
647926947304SEvan Yan 			/*
648026947304SEvan Yan 			 * currently support 32b address space
648126947304SEvan Yan 			 * assignments only.
648226947304SEvan Yan 			 */
648326947304SEvan Yan 			phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^
648426947304SEvan Yan 			    PCI_ADDR_MEM32;
648526947304SEvan Yan 
648626947304SEvan Yan 			break;
648726947304SEvan Yan 
648826947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
648926947304SEvan Yan 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
649026947304SEvan Yan 			/* allocate memory space from the allocator */
649126947304SEvan Yan 			if (ndi_ra_alloc(ddi_get_parent(dip),
649226947304SEvan Yan 			    &request, &answer, &alen,
649326947304SEvan Yan 			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
649426947304SEvan Yan 			    != NDI_SUCCESS) {
649526947304SEvan Yan 				DEBUG0("Failed to allocate 32b mem\n");
649626947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
649726947304SEvan Yan 				return (1);
649826947304SEvan Yan 			}
649926947304SEvan Yan 
650026947304SEvan Yan 			DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
650126947304SEvan Yan 			    PCICFG_HIADDR(answer),
650226947304SEvan Yan 			    PCICFG_LOADDR(answer),
650326947304SEvan Yan 			    alen);
650426947304SEvan Yan 
650526947304SEvan Yan 			/* program the low word */
650626947304SEvan Yan 
650726947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
650826947304SEvan Yan 			    (uint32_t)PCICFG_LOADDR(answer));
650926947304SEvan Yan 
651026947304SEvan Yan 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
651126947304SEvan Yan 
651226947304SEvan Yan 			break;
651326947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
651426947304SEvan Yan 			/* allocate I/O space from the allocator */
651526947304SEvan Yan 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
651626947304SEvan Yan 			if (ndi_ra_alloc(ddi_get_parent(dip),
651726947304SEvan Yan 			    &request, &answer, &alen,
651826947304SEvan Yan 			    NDI_RA_TYPE_IO, NDI_RA_PASS)
651926947304SEvan Yan 			    != NDI_SUCCESS) {
652026947304SEvan Yan 				DEBUG0("Failed to allocate I/O\n");
652126947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
652226947304SEvan Yan 				return (1);
652326947304SEvan Yan 			}
652426947304SEvan Yan 			DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
652526947304SEvan Yan 			    PCICFG_HIADDR(answer),
652626947304SEvan Yan 			    PCICFG_LOADDR(answer),
652726947304SEvan Yan 			    alen);
652826947304SEvan Yan 
652926947304SEvan Yan 			ddi_put32(h, (uint32_t *)v,
653026947304SEvan Yan 			    (uint32_t)PCICFG_LOADDR(answer));
653126947304SEvan Yan 
653226947304SEvan Yan 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
653326947304SEvan Yan 
653426947304SEvan Yan 			break;
653526947304SEvan Yan 		default:
653626947304SEvan Yan 			DEBUG0("Unknown register type\n");
653726947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
653826947304SEvan Yan 			return (1);
653926947304SEvan Yan 		} /* switch */
654026947304SEvan Yan 	}
654126947304SEvan Yan 
654226947304SEvan Yan 	/*
654326947304SEvan Yan 	 * Now that memory locations are assigned,
654426947304SEvan Yan 	 * update the assigned address property.
654526947304SEvan Yan 	 */
654626947304SEvan Yan 
654726947304SEvan Yan 	DEBUG1("updating assigned-addresss for %x\n",  phys_spec.pci_phys_hi);
654826947304SEvan Yan 
654926947304SEvan Yan 	if (pcicfg_update_assigned_prop(dip, &phys_spec)) {
655026947304SEvan Yan 		pcicfg_unmap_phys(&h, &config);
655126947304SEvan Yan 		return (1);
655226947304SEvan Yan 	}
655326947304SEvan Yan 
655426947304SEvan Yan 	pcicfg_unmap_phys(&h, &config);
655526947304SEvan Yan 
655626947304SEvan Yan 	return (0);
655726947304SEvan Yan }
655826947304SEvan Yan 
655926947304SEvan Yan static int
656026947304SEvan Yan pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec,
656126947304SEvan Yan     pcicfg_flags_t flags)
656226947304SEvan Yan {
656326947304SEvan Yan 	int offset;
656426947304SEvan Yan 	pci_regspec_t config;
656526947304SEvan Yan 	caddr_t virt, v;
656626947304SEvan Yan 	ddi_device_acc_attr_t acc;
656726947304SEvan Yan 	ddi_acc_handle_t h;
656826947304SEvan Yan 	ndi_ra_request_t request;
656926947304SEvan Yan 	int l;
657026947304SEvan Yan 
657126947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
657226947304SEvan Yan 
657326947304SEvan Yan 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
657426947304SEvan Yan 	config.pci_phys_hi &= ~PCI_REG_REG_M;
657526947304SEvan Yan 	config.pci_phys_mid = config.pci_phys_low = 0;
657626947304SEvan Yan 	config.pci_size_hi = config.pci_size_low = 0;
657726947304SEvan Yan 
657826947304SEvan Yan 	/*
657926947304SEvan Yan 	 * Map in configuration space (temporarily)
658026947304SEvan Yan 	 */
658126947304SEvan Yan 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
658226947304SEvan Yan 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
658326947304SEvan Yan 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
658426947304SEvan Yan 
658526947304SEvan Yan 	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
658626947304SEvan Yan 		DEBUG0("Can not map in config space\n");
658726947304SEvan Yan 		return (1);
658826947304SEvan Yan 	}
658926947304SEvan Yan 
659026947304SEvan Yan 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
659126947304SEvan Yan 
659226947304SEvan Yan 	v = virt + offset;
659326947304SEvan Yan 
659426947304SEvan Yan 	/*
659526947304SEvan Yan 	 * Use size stored in phys_spec parameter.
659626947304SEvan Yan 	 */
659726947304SEvan Yan 	l = phys_spec.pci_size_low;
659826947304SEvan Yan 
659926947304SEvan Yan 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
660026947304SEvan Yan 
660126947304SEvan Yan 		/* free memory back to the allocator */
660226947304SEvan Yan 		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
660326947304SEvan Yan 		    l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
660426947304SEvan Yan 			DEBUG0("(ROM)Can not free 32b mem");
660526947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
660626947304SEvan Yan 			return (1);
660726947304SEvan Yan 		}
660826947304SEvan Yan 
660926947304SEvan Yan 		/* Unmap the BAR by writing a zero */
661026947304SEvan Yan 
661126947304SEvan Yan 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0)
661226947304SEvan Yan 			ddi_put32(h, (uint32_t *)v, (uint32_t)0);
661326947304SEvan Yan 	} else {
661426947304SEvan Yan 
661526947304SEvan Yan 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
661626947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
661726947304SEvan Yan 			/* free memory back to the allocator */
661826947304SEvan Yan 			if (ndi_ra_free(ddi_get_parent(dip),
661926947304SEvan Yan 			    PCICFG_LADDR(phys_spec.pci_phys_low,
662026947304SEvan Yan 			    phys_spec.pci_phys_mid),
662126947304SEvan Yan 			    l, NDI_RA_TYPE_MEM,
662226947304SEvan Yan 			    NDI_RA_PASS) != NDI_SUCCESS) {
662326947304SEvan Yan 				DEBUG0("Can not free 64b mem");
662426947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
662526947304SEvan Yan 				return (1);
662626947304SEvan Yan 			}
662726947304SEvan Yan 
662826947304SEvan Yan 			break;
662926947304SEvan Yan 
663026947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
663126947304SEvan Yan 			/* free memory back to the allocator */
663226947304SEvan Yan 			if (ndi_ra_free(ddi_get_parent(dip),
663326947304SEvan Yan 			    phys_spec.pci_phys_low,
663426947304SEvan Yan 			    l, NDI_RA_TYPE_MEM,
663526947304SEvan Yan 			    NDI_RA_PASS) != NDI_SUCCESS) {
663626947304SEvan Yan 				DEBUG0("Can not free 32b mem");
663726947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
663826947304SEvan Yan 				return (1);
663926947304SEvan Yan 			}
664026947304SEvan Yan 
664126947304SEvan Yan 			break;
664226947304SEvan Yan 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
664326947304SEvan Yan 			/* free I/O space back to the allocator */
664426947304SEvan Yan 			if (ndi_ra_free(ddi_get_parent(dip),
664526947304SEvan Yan 			    phys_spec.pci_phys_low,
664626947304SEvan Yan 			    l, NDI_RA_TYPE_IO,
664726947304SEvan Yan 			    NDI_RA_PASS) != NDI_SUCCESS) {
664826947304SEvan Yan 				DEBUG0("Can not free I/O space");
664926947304SEvan Yan 				pcicfg_unmap_phys(&h, &config);
665026947304SEvan Yan 				return (1);
665126947304SEvan Yan 			}
665226947304SEvan Yan 
665326947304SEvan Yan 			break;
665426947304SEvan Yan 		default:
665526947304SEvan Yan 			DEBUG0("Unknown register type\n");
665626947304SEvan Yan 			pcicfg_unmap_phys(&h, &config);
665726947304SEvan Yan 			return (1);
665826947304SEvan Yan 		} /* switch */
665926947304SEvan Yan 	}
666026947304SEvan Yan 
666126947304SEvan Yan 	/*
666226947304SEvan Yan 	 * Now that memory locations are assigned,
666326947304SEvan Yan 	 * update the assigned address property.
666426947304SEvan Yan 	 */
666526947304SEvan Yan 
666626947304SEvan Yan 	DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi);
666726947304SEvan Yan 
666826947304SEvan Yan 	if (pcicfg_remove_assigned_prop(dip, &phys_spec)) {
666926947304SEvan Yan 		pcicfg_unmap_phys(&h, &config);
667026947304SEvan Yan 		return (1);
667126947304SEvan Yan 	}
667226947304SEvan Yan 
667326947304SEvan Yan 	pcicfg_unmap_phys(&h, &config);
667426947304SEvan Yan 
667526947304SEvan Yan 	return (0);
667626947304SEvan Yan }
667726947304SEvan Yan 
667826947304SEvan Yan static int
667926947304SEvan Yan pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
668026947304SEvan Yan {
668126947304SEvan Yan 	int		alen, num_entries, i;
668226947304SEvan Yan 	pci_regspec_t	*assigned, *assigned_copy;
668326947304SEvan Yan 	uint_t		status;
668426947304SEvan Yan 
668526947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
668626947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &alen);
668726947304SEvan Yan 	switch (status) {
668826947304SEvan Yan 		case DDI_PROP_SUCCESS:
668926947304SEvan Yan 		break;
669026947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
669126947304SEvan Yan 			DEBUG0("no memory for assigned-addresses property\n");
669226947304SEvan Yan 			return (1);
669326947304SEvan Yan 		default:
669426947304SEvan Yan 			DEBUG0("assigned-addresses property does not exist\n");
669526947304SEvan Yan 			return (0);
669626947304SEvan Yan 	}
669726947304SEvan Yan 
669826947304SEvan Yan 	/*
669926947304SEvan Yan 	 * Make a copy of old assigned-addresses property.
670026947304SEvan Yan 	 */
670126947304SEvan Yan 	assigned_copy = kmem_alloc(alen, KM_SLEEP);
670226947304SEvan Yan 	bcopy(assigned, assigned_copy, alen);
670326947304SEvan Yan 
670426947304SEvan Yan 	status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses");
670526947304SEvan Yan 
670626947304SEvan Yan 	if (status != DDI_PROP_SUCCESS) {
670726947304SEvan Yan 		/*
670826947304SEvan Yan 		 * If "assigned-addresses" is retrieved from PROM, the
670926947304SEvan Yan 		 * ndi_prop_remove() will fail.
671026947304SEvan Yan 		 */
671126947304SEvan Yan 		DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n",
671226947304SEvan Yan 		    oldone->pci_phys_hi);
671326947304SEvan Yan 
671426947304SEvan Yan 		/*
671526947304SEvan Yan 		 * Free up allocated memory
671626947304SEvan Yan 		 */
671726947304SEvan Yan 		kmem_free(assigned_copy, alen);
671826947304SEvan Yan 		kmem_free((caddr_t)assigned, alen);
671926947304SEvan Yan 
672026947304SEvan Yan 		return (0);
672126947304SEvan Yan 	}
672226947304SEvan Yan 
672326947304SEvan Yan 	num_entries = alen / sizeof (pci_regspec_t);
672426947304SEvan Yan 
672526947304SEvan Yan 	/*
672626947304SEvan Yan 	 * Rebuild the assigned-addresses property.
672726947304SEvan Yan 	 */
672826947304SEvan Yan 	for (i = 0; i < num_entries; i++) {
672926947304SEvan Yan 		if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) {
673026947304SEvan Yan 			(void) pcicfg_update_assigned_prop(dip,
673126947304SEvan Yan 			    &assigned_copy[i]);
673226947304SEvan Yan 		}
673326947304SEvan Yan 	}
673426947304SEvan Yan 
673526947304SEvan Yan 	/*
673626947304SEvan Yan 	 * Free the copy of the original assigned-addresses.
673726947304SEvan Yan 	 */
673826947304SEvan Yan 	kmem_free(assigned_copy, alen);
673926947304SEvan Yan 
674026947304SEvan Yan 	/*
674126947304SEvan Yan 	 * Don't forget to free up memory from ddi_getlongprop
674226947304SEvan Yan 	 */
674326947304SEvan Yan 	kmem_free((caddr_t)assigned, alen);
674426947304SEvan Yan 
674526947304SEvan Yan 	return (0);
674626947304SEvan Yan }
674726947304SEvan Yan 
674826947304SEvan Yan static int
674926947304SEvan Yan pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
675026947304SEvan Yan 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
675126947304SEvan Yan 	ddi_acc_handle_t *handlep)
675226947304SEvan Yan {
675326947304SEvan Yan 	ddi_map_req_t mr;
675426947304SEvan Yan 	ddi_acc_hdl_t *hp;
675526947304SEvan Yan 	int result;
675626947304SEvan Yan 
675726947304SEvan Yan 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
675826947304SEvan Yan 	hp = impl_acc_hdl_get(*handlep);
675926947304SEvan Yan 	hp->ah_vers = VERS_ACCHDL;
676026947304SEvan Yan 	hp->ah_dip = dip;
676126947304SEvan Yan 	hp->ah_rnumber = 0;
676226947304SEvan Yan 	hp->ah_offset = 0;
676326947304SEvan Yan 	hp->ah_len = 0;
676426947304SEvan Yan 	hp->ah_acc = *accattrp;
676526947304SEvan Yan 
676626947304SEvan Yan 	mr.map_op = DDI_MO_MAP_LOCKED;
676726947304SEvan Yan 	mr.map_type = DDI_MT_REGSPEC;
676826947304SEvan Yan 	mr.map_obj.rp = (struct regspec *)phys_spec;
676926947304SEvan Yan 	mr.map_prot = PROT_READ | PROT_WRITE;
677026947304SEvan Yan 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
677126947304SEvan Yan 	mr.map_handlep = hp;
677226947304SEvan Yan 	mr.map_vers = DDI_MAP_VERSION;
677326947304SEvan Yan 
677426947304SEvan Yan 	result = ddi_map(dip, &mr, 0, 0, addrp);
677526947304SEvan Yan 
677626947304SEvan Yan 	if (result != DDI_SUCCESS) {
677726947304SEvan Yan 		impl_acc_hdl_free(*handlep);
677826947304SEvan Yan 		*handlep = (ddi_acc_handle_t)NULL;
677926947304SEvan Yan 	} else {
678026947304SEvan Yan 		hp->ah_addr = *addrp;
678126947304SEvan Yan 	}
678226947304SEvan Yan 
678326947304SEvan Yan 	return (result);
678426947304SEvan Yan }
678526947304SEvan Yan 
678626947304SEvan Yan void
678726947304SEvan Yan pcicfg_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
678826947304SEvan Yan {
678926947304SEvan Yan 	ddi_map_req_t mr;
679026947304SEvan Yan 	ddi_acc_hdl_t *hp;
679126947304SEvan Yan 
679226947304SEvan Yan 	hp = impl_acc_hdl_get(*handlep);
679326947304SEvan Yan 	ASSERT(hp);
679426947304SEvan Yan 
679526947304SEvan Yan 	mr.map_op = DDI_MO_UNMAP;
679626947304SEvan Yan 	mr.map_type = DDI_MT_REGSPEC;
679726947304SEvan Yan 	mr.map_obj.rp = (struct regspec *)ph;
679826947304SEvan Yan 	mr.map_prot = PROT_READ | PROT_WRITE;
679926947304SEvan Yan 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
680026947304SEvan Yan 	mr.map_handlep = hp;
680126947304SEvan Yan 	mr.map_vers = DDI_MAP_VERSION;
680226947304SEvan Yan 
680326947304SEvan Yan 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
680426947304SEvan Yan 	    hp->ah_len, &hp->ah_addr);
680526947304SEvan Yan 
680626947304SEvan Yan 	impl_acc_hdl_free(*handlep);
680726947304SEvan Yan 	*handlep = (ddi_acc_handle_t)NULL;
680826947304SEvan Yan }
680926947304SEvan Yan 
681026947304SEvan Yan static int
681126947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip)
681226947304SEvan Yan {
681326947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
681426947304SEvan Yan 		return (DDI_FAILURE);
681526947304SEvan Yan 
681626947304SEvan Yan 	/*
681726947304SEvan Yan 	 * Until we have resource balancing, dynamically configure
681826947304SEvan Yan 	 * ARI functions without firmware assistamce.
681926947304SEvan Yan 	 */
682026947304SEvan Yan 	return (DDI_FAILURE);
682126947304SEvan Yan }
682226947304SEvan Yan 
682326947304SEvan Yan #ifdef DEBUG
682426947304SEvan Yan static void
682526947304SEvan Yan debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
682626947304SEvan Yan 	uintptr_t a4, uintptr_t a5)
682726947304SEvan Yan {
682826947304SEvan Yan 	if (pcicfg_debug == 1) {
682926947304SEvan Yan 		prom_printf("pcicfg: ");
683026947304SEvan Yan 		prom_printf(fmt, a1, a2, a3, a4, a5);
683126947304SEvan Yan 	} else
683226947304SEvan Yan 		if (pcicfg_debug)
683326947304SEvan Yan 			cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
683426947304SEvan Yan }
683526947304SEvan Yan #endif
6836c0da6274SZhi-Jun Robin Fu 
6837c0da6274SZhi-Jun Robin Fu /*
6838c0da6274SZhi-Jun Robin Fu  * Return true if the devinfo node is in a PCI Express hierarchy.
6839c0da6274SZhi-Jun Robin Fu  */
6840c0da6274SZhi-Jun Robin Fu static boolean_t
6841c0da6274SZhi-Jun Robin Fu is_pcie_fabric(dev_info_t *dip)
6842c0da6274SZhi-Jun Robin Fu {
6843c0da6274SZhi-Jun Robin Fu 	dev_info_t *root = ddi_root_node();
6844c0da6274SZhi-Jun Robin Fu 	dev_info_t *pdip;
6845c0da6274SZhi-Jun Robin Fu 	boolean_t found = B_FALSE;
6846c0da6274SZhi-Jun Robin Fu 	char *bus;
6847c0da6274SZhi-Jun Robin Fu 
6848c0da6274SZhi-Jun Robin Fu 	/*
6849c0da6274SZhi-Jun Robin Fu 	 * Does this device reside in a pcie fabric ?
6850c0da6274SZhi-Jun Robin Fu 	 */
6851c0da6274SZhi-Jun Robin Fu 	for (pdip = dip; pdip && (pdip != root) && !found;
6852c0da6274SZhi-Jun Robin Fu 	    pdip = ddi_get_parent(pdip)) {
6853c0da6274SZhi-Jun Robin Fu 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
6854c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_DONTPASS, "device_type", &bus) !=
6855c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_SUCCESS)
6856c0da6274SZhi-Jun Robin Fu 			break;
6857c0da6274SZhi-Jun Robin Fu 
6858c0da6274SZhi-Jun Robin Fu 		if (strcmp(bus, "pciex") == 0)
6859c0da6274SZhi-Jun Robin Fu 			found = B_TRUE;
6860c0da6274SZhi-Jun Robin Fu 
6861c0da6274SZhi-Jun Robin Fu 		ddi_prop_free(bus);
6862c0da6274SZhi-Jun Robin Fu 	}
6863c0da6274SZhi-Jun Robin Fu 
6864c0da6274SZhi-Jun Robin Fu 	return (found);
6865c0da6274SZhi-Jun Robin Fu }
6866