xref: /illumos-gate/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c (revision bd97c7ce2344fa3252d8785c35895490916bc79b)
123c35297Sanish /*
223c35297Sanish  * CDDL HEADER START
323c35297Sanish  *
423c35297Sanish  * The contents of this file are subject to the terms of the
523c35297Sanish  * Common Development and Distribution License (the "License").
623c35297Sanish  * You may not use this file except in compliance with the License.
723c35297Sanish  *
823c35297Sanish  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
923c35297Sanish  * or http://www.opensolaris.org/os/licensing.
1023c35297Sanish  * See the License for the specific language governing permissions
1123c35297Sanish  * and limitations under the License.
1223c35297Sanish  *
1323c35297Sanish  * When distributing Covered Code, include this CDDL HEADER in each
1423c35297Sanish  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1523c35297Sanish  * If applicable, add the following below this CDDL HEADER, with the
1623c35297Sanish  * fields enclosed by brackets "[]" replaced with your own identifying
1723c35297Sanish  * information: Portions Copyright [yyyy] [name of copyright owner]
1823c35297Sanish  *
1923c35297Sanish  * CDDL HEADER END
2023c35297Sanish  */
2123c35297Sanish /*
227f59ab1cSAlan Adamson, SD OSSD  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23ffb64830SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
24b31f5cf7SDan Cross  * Copyright 2023 Oxide Computer Company
2523c35297Sanish  */
2623c35297Sanish 
2723c35297Sanish /*
2823c35297Sanish  *     PCI configurator (pcicfg)
2923c35297Sanish  */
3023c35297Sanish 
3123c35297Sanish #include <sys/sysmacros.h>
3223c35297Sanish #include <sys/conf.h>
3323c35297Sanish #include <sys/kmem.h>
3423c35297Sanish #include <sys/debug.h>
3523c35297Sanish #include <sys/modctl.h>
3623c35297Sanish #include <sys/autoconf.h>
3723c35297Sanish #include <sys/hwconf.h>
3823c35297Sanish #include <sys/pcie.h>
3926947304SEvan Yan #include <sys/pcie_impl.h>
4049fbdd30SErwin T Tsaur #include <sys/pci_cap.h>
4123c35297Sanish #include <sys/ddi.h>
4223c35297Sanish #include <sys/sunndi.h>
4323c35297Sanish #include <sys/hotplug/pci/pcicfg.h>
4423c35297Sanish #include <sys/ndi_impldefs.h>
45c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
46*bd97c7ceSRobert Mustacchi #include <sys/pci_props.h>
4723c35297Sanish 
4823c35297Sanish /*
4923c35297Sanish  * ************************************************************************
5023c35297Sanish  * *** Implementation specific local data structures/definitions.	***
5123c35297Sanish  * ************************************************************************
5223c35297Sanish  */
5323c35297Sanish 
5423c35297Sanish static	int	pcicfg_start_devno = 0;	/* for Debug only */
5523c35297Sanish 
5626947304SEvan Yan #define	PCICFG_MAX_ARI_FUNCTION 256
5726947304SEvan Yan 
5823c35297Sanish #define	PCICFG_NODEVICE 42
5923c35297Sanish #define	PCICFG_NOMEMORY 43
6023c35297Sanish #define	PCICFG_NOMULTI	44
615af4ae46Sjveta #define	PCICFG_NORESRC	45
6223c35297Sanish 
6323c35297Sanish #define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & \
6423c35297Sanish 	0xFFFFFFFF00000000ULL)>> 32))
6523c35297Sanish #define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
6623c35297Sanish #define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
6723c35297Sanish 
6823c35297Sanish #define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
6923c35297Sanish #define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
7023c35297Sanish #define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
7123c35297Sanish #define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
7223c35297Sanish 
7323c35297Sanish #define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
7423c35297Sanish #define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
7523c35297Sanish 
7623c35297Sanish #define	PCICFG_MEMGRAN 0x100000
7723c35297Sanish #define	PCICFG_IOGRAN 0x1000
7823c35297Sanish #define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
7923c35297Sanish 
8023c35297Sanish #define	PCICFG_MEM_MULT 4
8123c35297Sanish #define	PCICFG_IO_MULT 4
8223c35297Sanish #define	PCICFG_RANGE_LEN 3 /* Number of range entries */
8323c35297Sanish 
8423c35297Sanish static int pcicfg_slot_busnums = 8;
8523c35297Sanish static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8623c35297Sanish static int pcicfg_slot_pf_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8723c35297Sanish static int pcicfg_slot_iosize = 64 * PCICFG_IOGRAN; /* 64K per slot */
8823c35297Sanish static int pcicfg_sec_reset_delay = 3000000;
8923c35297Sanish 
9023c35297Sanish typedef struct hole hole_t;
9123c35297Sanish 
9223c35297Sanish struct hole {
9323c35297Sanish 	uint64_t	start;
9423c35297Sanish 	uint64_t	len;
9523c35297Sanish 	hole_t		*next;
9623c35297Sanish };
9723c35297Sanish 
9823c35297Sanish typedef struct pcicfg_phdl pcicfg_phdl_t;
9923c35297Sanish 
10023c35297Sanish struct pcicfg_phdl {
10123c35297Sanish 
10223c35297Sanish 	dev_info_t	*dip;		/* Associated with the bridge */
10323c35297Sanish 	dev_info_t	*top_dip;	/* top node of the attach point */
10423c35297Sanish 	pcicfg_phdl_t	*next;
10523c35297Sanish 
10623c35297Sanish 	/* non-prefetchable memory space */
10723c35297Sanish 	uint64_t	memory_base;	/* Memory base for this attach point */
10823c35297Sanish 	uint64_t	memory_last;
10923c35297Sanish 	uint64_t	memory_len;
11023c35297Sanish 
11123c35297Sanish 	/* prefetchable memory space */
11226947304SEvan Yan 	uint64_t	pf_memory_base;	/* PF Memory base for this Connection */
11323c35297Sanish 	uint64_t	pf_memory_last;
11423c35297Sanish 	uint64_t	pf_memory_len;
11523c35297Sanish 
11623c35297Sanish 	/* io space */
11723c35297Sanish 	uint32_t	io_base;	/* I/O base for this attach point */
11823c35297Sanish 	uint32_t	io_last;
11923c35297Sanish 	uint32_t	io_len;
12023c35297Sanish 
12123c35297Sanish 	int		error;
12223c35297Sanish 	uint_t		highest_bus;	/* Highest bus seen on the probe */
12323c35297Sanish 
12423c35297Sanish 	hole_t		mem_hole;	/* Memory hole linked list. */
12523c35297Sanish 	hole_t		pf_mem_hole;	/* PF Memory hole linked list. */
12623c35297Sanish 	hole_t		io_hole;	/* IO hole linked list */
12723c35297Sanish 
12823c35297Sanish 	ndi_ra_request_t mem_req;	/* allocator request for memory */
12923c35297Sanish 	ndi_ra_request_t pf_mem_req;	/* allocator request for PF memory */
13023c35297Sanish 	ndi_ra_request_t io_req;	/* allocator request for I/O */
13123c35297Sanish };
13223c35297Sanish 
13323c35297Sanish struct pcicfg_standard_prop_entry {
13423c35297Sanish     uchar_t *name;
13523c35297Sanish     uint_t  config_offset;
13623c35297Sanish     uint_t  size;
13723c35297Sanish };
13823c35297Sanish 
13923c35297Sanish 
14023c35297Sanish struct pcicfg_name_entry {
14123c35297Sanish     uint32_t class_code;
14223c35297Sanish     char  *name;
14323c35297Sanish };
14423c35297Sanish 
14523c35297Sanish struct pcicfg_find_ctrl {
14623c35297Sanish 	uint_t		device;
14723c35297Sanish 	uint_t		function;
14823c35297Sanish 	dev_info_t	*dip;
14923c35297Sanish };
15023c35297Sanish 
15123c35297Sanish /*
15223c35297Sanish  * List of Indirect Config Map Devices. At least the intent of the
15323c35297Sanish  * design is to look for a device in this list during the configure
15423c35297Sanish  * operation, and if the device is listed here, then it is a nontransparent
15523c35297Sanish  * bridge, hence load the driver and avail the config map services from
15623c35297Sanish  * the driver. Class and Subclass should be as defined in the PCI specs
15723c35297Sanish  * ie. class is 0x6, and subclass is 0x9.
15823c35297Sanish  */
15923c35297Sanish static struct {
16023c35297Sanish 	uint8_t		mem_range_bar_offset;
16123c35297Sanish 	uint8_t		io_range_bar_offset;
16223c35297Sanish 	uint8_t		prefetch_mem_range_bar_offset;
16323c35297Sanish } pcicfg_indirect_map_devs[] = {
16423c35297Sanish 	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
16523c35297Sanish 	0,	0,	0,
16623c35297Sanish };
16723c35297Sanish 
16823c35297Sanish #define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
16923c35297Sanish 	(\
17023c35297Sanish 	((ulong_t)(busnum & 0xff) << 16)    |\
17123c35297Sanish 	((ulong_t)(devnum & 0x1f) << 11)    |\
17223c35297Sanish 	((ulong_t)(funcnum & 0x7) <<  8)    |\
17323c35297Sanish 	((ulong_t)(register & 0x3f)))
17423c35297Sanish 
17523c35297Sanish /*
17623c35297Sanish  * debug macros:
17723c35297Sanish  */
17823c35297Sanish #if	defined(DEBUG)
17923c35297Sanish extern void prom_printf(const char *, ...);
18023c35297Sanish 
18123c35297Sanish /*
18223c35297Sanish  * Following values are defined for this debug flag.
18323c35297Sanish  *
18423c35297Sanish  * 1 = dump configuration header only.
18523c35297Sanish  * 2 = dump generic debug data only (no config header dumped)
18623c35297Sanish  * 3 = dump everything (both 1 and 2)
18723c35297Sanish  */
18823c35297Sanish int pcicfg_debug = 0;
18923c35297Sanish 
19023c35297Sanish static void debug(char *, uintptr_t, uintptr_t,
19123c35297Sanish 	uintptr_t, uintptr_t, uintptr_t);
19223c35297Sanish 
19323c35297Sanish #define	DEBUG0(fmt)\
19423c35297Sanish 	debug(fmt, 0, 0, 0, 0, 0);
19523c35297Sanish #define	DEBUG1(fmt, a1)\
19623c35297Sanish 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
19723c35297Sanish #define	DEBUG2(fmt, a1, a2)\
19823c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
19923c35297Sanish #define	DEBUG3(fmt, a1, a2, a3)\
20023c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20123c35297Sanish 		(uintptr_t)(a3), 0, 0);
20223c35297Sanish #define	DEBUG4(fmt, a1, a2, a3, a4)\
20323c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20423c35297Sanish 		(uintptr_t)(a3), (uintptr_t)(a4), 0);
20523c35297Sanish #define	DEBUG5(fmt, a1, a2, a3, a4, a5)\
20623c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20723c35297Sanish 		(uintptr_t)(a3), (uintptr_t)(a4), (uintptr_t)(a5));
20823c35297Sanish #else
20923c35297Sanish #define	DEBUG0(fmt)
21023c35297Sanish #define	DEBUG1(fmt, a1)
21123c35297Sanish #define	DEBUG2(fmt, a1, a2)
21223c35297Sanish #define	DEBUG3(fmt, a1, a2, a3)
21323c35297Sanish #define	DEBUG4(fmt, a1, a2, a3, a4)
21423c35297Sanish #define	DEBUG5(fmt, a1, a2, a3, a4, a5)
21523c35297Sanish #endif
21623c35297Sanish 
21723c35297Sanish /*
21823c35297Sanish  * forward declarations for routines defined in this module (called here)
21923c35297Sanish  */
22023c35297Sanish 
22123c35297Sanish static int pcicfg_add_config_reg(dev_info_t *,
22223c35297Sanish     uint_t, uint_t, uint_t);
22323c35297Sanish static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
224c0da6274SZhi-Jun Robin Fu     uint_t *, pcicfg_flags_t, boolean_t);
22523c35297Sanish static int pcicfg_match_dev(dev_info_t *, void *);
22623c35297Sanish static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
22723c35297Sanish static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
22823c35297Sanish static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
22923c35297Sanish static int pcicfg_destroy_phdl(dev_info_t *);
23023c35297Sanish static int pcicfg_sum_resources(dev_info_t *, void *);
23123c35297Sanish static int pcicfg_device_assign(dev_info_t *);
23223c35297Sanish static int pcicfg_bridge_assign(dev_info_t *, void *);
23326947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *);
23426947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
23523c35297Sanish static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23623c35297Sanish static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23723c35297Sanish static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
23823c35297Sanish static void pcicfg_device_on(ddi_acc_handle_t);
23923c35297Sanish static void pcicfg_device_off(ddi_acc_handle_t);
24023c35297Sanish static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
24123c35297Sanish static int pcicfg_free_bridge_resources(dev_info_t *);
24223c35297Sanish static int pcicfg_free_device_resources(dev_info_t *);
243c0da6274SZhi-Jun Robin Fu static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
24423c35297Sanish static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
24523c35297Sanish static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
24623c35297Sanish static void pcicfg_config_teardown(ddi_acc_handle_t *);
24723c35297Sanish static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24823c35297Sanish static void pcicfg_get_pf_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24923c35297Sanish static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
25023c35297Sanish static int pcicfg_update_ranges_prop(dev_info_t *, ppb_ranges_t *);
25123c35297Sanish static int pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
25223c35297Sanish static uint_t pcicfg_ntbridge_child(dev_info_t *);
25323c35297Sanish static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
25423c35297Sanish     uint64_t *, uint_t);
25523c35297Sanish static int pcicfg_is_ntbridge(dev_info_t *);
25623c35297Sanish static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
25723c35297Sanish static int pcicfg_ntbridge_configure_done(dev_info_t *);
25823c35297Sanish static int pcicfg_ntbridge_program_child(dev_info_t *);
25923c35297Sanish static uint_t pcicfg_ntbridge_unconfigure(dev_info_t *);
26023c35297Sanish static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
26123c35297Sanish static void pcicfg_free_hole(hole_t *);
26223c35297Sanish static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
26323c35297Sanish static int pcicfg_device_type(dev_info_t *, ddi_acc_handle_t *);
26423c35297Sanish static void pcicfg_update_phdl(dev_info_t *, uint8_t, uint8_t);
26523c35297Sanish static int pcicfg_get_cap(ddi_acc_handle_t, uint8_t);
26623c35297Sanish static uint8_t pcicfg_get_nslots(dev_info_t *, ddi_acc_handle_t);
26723c35297Sanish static int pcicfg_pcie_device_type(dev_info_t *, ddi_acc_handle_t);
26823c35297Sanish static int pcicfg_pcie_port_type(dev_info_t *, ddi_acc_handle_t);
26923c35297Sanish static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
270c0da6274SZhi-Jun Robin Fu 	uint_t *, boolean_t);
27123c35297Sanish static int pcicfg_find_resource_end(dev_info_t *, void *);
272c0da6274SZhi-Jun Robin Fu static boolean_t is_pcie_fabric(dev_info_t *);
27323c35297Sanish 
27426947304SEvan Yan static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
27526947304SEvan Yan static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
27626947304SEvan Yan static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
27726947304SEvan Yan     uint32_t, uint32_t, uint_t);
27826947304SEvan Yan static int pcicfg_ari_configure(dev_info_t *);
27926947304SEvan Yan 
28023c35297Sanish #ifdef DEBUG
28123c35297Sanish static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
28223c35297Sanish static void pcicfg_dump_device_config(ddi_acc_handle_t);
28323c35297Sanish static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
28423c35297Sanish static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
28523c35297Sanish 
28623c35297Sanish #define	PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
28723c35297Sanish #define	PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
28823c35297Sanish #define	PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
28923c35297Sanish #else
29023c35297Sanish #define	PCICFG_DUMP_COMMON_CONFIG(handle)
29123c35297Sanish #define	PCICFG_DUMP_DEVICE_CONFIG(handle)
29223c35297Sanish #define	PCICFG_DUMP_BRIDGE_CONFIG(handle)
29323c35297Sanish #endif
29423c35297Sanish 
29523c35297Sanish static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
29623c35297Sanish static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
29723c35297Sanish 
29823c35297Sanish #ifndef _DONT_USE_1275_GENERIC_NAMES
29923c35297Sanish /*
30023c35297Sanish  * Class code table
30123c35297Sanish  */
30223c35297Sanish static struct pcicfg_name_entry pcicfg_class_lookup [] = {
30323c35297Sanish 
30423c35297Sanish 	{ 0x001, "display" },
30523c35297Sanish 	{ 0x100, "scsi" },
30623c35297Sanish 	{ 0x101, "ide" },
30723c35297Sanish 	{ 0x102, "fdc" },
30823c35297Sanish 	{ 0x103, "ipi" },
30923c35297Sanish 	{ 0x104, "raid" },
31023c35297Sanish 	{ 0x105, "ata" },
31123c35297Sanish 	{ 0x106, "sata" },
31223c35297Sanish 	{ 0x200, "ethernet" },
31323c35297Sanish 	{ 0x201, "token-ring" },
31423c35297Sanish 	{ 0x202, "fddi" },
31523c35297Sanish 	{ 0x203, "atm" },
31623c35297Sanish 	{ 0x204, "isdn" },
31723c35297Sanish 	{ 0x206, "mcd" },
31823c35297Sanish 	{ 0x300, "display" },
31923c35297Sanish 	{ 0x400, "video" },
32023c35297Sanish 	{ 0x401, "sound" },
32123c35297Sanish 	{ 0x500, "memory" },
32223c35297Sanish 	{ 0x501, "flash" },
32323c35297Sanish 	{ 0x600, "host" },
32423c35297Sanish 	{ 0x601, "isa" },
32523c35297Sanish 	{ 0x602, "eisa" },
32623c35297Sanish 	{ 0x603, "mca" },
32723c35297Sanish 	{ 0x604, "pci" },
32823c35297Sanish 	{ 0x605, "pcmcia" },
32923c35297Sanish 	{ 0x606, "nubus" },
33023c35297Sanish 	{ 0x607, "cardbus" },
33123c35297Sanish 	{ 0x609, "pci" },
33223c35297Sanish 	{ 0x60a, "ib-pci" },
33323c35297Sanish 	{ 0x700, "serial" },
33423c35297Sanish 	{ 0x701, "parallel" },
33523c35297Sanish 	{ 0x800, "interrupt-controller" },
33623c35297Sanish 	{ 0x801, "dma-controller" },
33723c35297Sanish 	{ 0x802, "timer" },
33823c35297Sanish 	{ 0x803, "rtc" },
33923c35297Sanish 	{ 0x900, "keyboard" },
34023c35297Sanish 	{ 0x901, "pen" },
34123c35297Sanish 	{ 0x902, "mouse" },
34223c35297Sanish 	{ 0xa00, "dock" },
34323c35297Sanish 	{ 0xb00, "cpu" },
34423c35297Sanish 	{ 0xb01, "cpu" },
34523c35297Sanish 	{ 0xb02, "cpu" },
34623c35297Sanish 	{ 0xb10, "cpu" },
34723c35297Sanish 	{ 0xb20, "cpu" },
34823c35297Sanish 	{ 0xb30, "cpu" },
34923c35297Sanish 	{ 0xb40, "coproc" },
35023c35297Sanish 	{ 0xc00, "firewire" },
35123c35297Sanish 	{ 0xc01, "access-bus" },
35223c35297Sanish 	{ 0xc02, "ssa" },
35323c35297Sanish 	{ 0xc03, "usb" },
35423c35297Sanish 	{ 0xc04, "fibre-channel" },
35523c35297Sanish 	{ 0xc05, "smbus" },
35623c35297Sanish 	{ 0xc06, "ib" },
35723c35297Sanish 	{ 0xd00, "irda" },
35823c35297Sanish 	{ 0xd01, "ir" },
35923c35297Sanish 	{ 0xd10, "rf" },
36023c35297Sanish 	{ 0xd11, "btooth" },
36123c35297Sanish 	{ 0xd12, "brdband" },
36223c35297Sanish 	{ 0xd20, "802.11a" },
36323c35297Sanish 	{ 0xd21, "802.11b" },
36423c35297Sanish 	{ 0xe00, "i2o" },
36523c35297Sanish 	{ 0xf01, "tv" },
36623c35297Sanish 	{ 0xf02, "audio" },
36723c35297Sanish 	{ 0xf03, "voice" },
36823c35297Sanish 	{ 0xf04, "data" },
36923c35297Sanish 	{ 0, 0 }
37023c35297Sanish };
37123c35297Sanish #endif /* _DONT_USE_1275_GENERIC_NAMES */
37223c35297Sanish 
37323c35297Sanish /*
37423c35297Sanish  * Module control operations
37523c35297Sanish  */
37623c35297Sanish 
37723c35297Sanish extern struct mod_ops mod_miscops;
37823c35297Sanish 
37923c35297Sanish static struct modlmisc modlmisc = {
38023c35297Sanish 	&mod_miscops, /* Type of module */
381613b2871SRichard Bean 	"PCI configurator"
38223c35297Sanish };
38323c35297Sanish 
38423c35297Sanish static struct modlinkage modlinkage = {
38523c35297Sanish 	MODREV_1, (void *)&modlmisc, NULL
38623c35297Sanish };
38723c35297Sanish 
38823c35297Sanish 
38923c35297Sanish #ifdef DEBUG
39023c35297Sanish 
39123c35297Sanish static void
pcicfg_dump_common_config(ddi_acc_handle_t config_handle)39223c35297Sanish pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
39323c35297Sanish {
39423c35297Sanish 	if ((pcicfg_debug & 1) == 0)
39523c35297Sanish 		return;
39623c35297Sanish 	prom_printf(" Vendor ID   = [0x%x]\n",
39723c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_VENID));
39823c35297Sanish 	prom_printf(" Device ID   = [0x%x]\n",
39923c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
40023c35297Sanish 	prom_printf(" Command REG = [0x%x]\n",
40123c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_COMM));
40223c35297Sanish 	prom_printf(" Status  REG = [0x%x]\n",
40323c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_STAT));
40423c35297Sanish 	prom_printf(" Revision ID = [0x%x]\n",
40523c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_REVID));
40623c35297Sanish 	prom_printf(" Prog Class  = [0x%x]\n",
40723c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
40823c35297Sanish 	prom_printf(" Dev Class   = [0x%x]\n",
40923c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
41023c35297Sanish 	prom_printf(" Base Class  = [0x%x]\n",
41123c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
41223c35297Sanish 	prom_printf(" Device ID   = [0x%x]\n",
41323c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
41423c35297Sanish 	prom_printf(" Header Type = [0x%x]\n",
41523c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_HEADER));
41623c35297Sanish 	prom_printf(" BIST        = [0x%x]\n",
41723c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_BIST));
41823c35297Sanish 	prom_printf(" BASE 0      = [0x%x]\n",
41923c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_BASE0));
42023c35297Sanish 	prom_printf(" BASE 1      = [0x%x]\n",
42123c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_BASE1));
42223c35297Sanish 
42323c35297Sanish }
42423c35297Sanish 
42523c35297Sanish static void
pcicfg_dump_device_config(ddi_acc_handle_t config_handle)42623c35297Sanish pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
42723c35297Sanish {
42823c35297Sanish 	if ((pcicfg_debug & 1) == 0)
42923c35297Sanish 		return;
43023c35297Sanish 	pcicfg_dump_common_config(config_handle);
43123c35297Sanish 
43223c35297Sanish 	prom_printf(" BASE 2      = [0x%x]\n",
43323c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_BASE2));
43423c35297Sanish 	prom_printf(" BASE 3      = [0x%x]\n",
43523c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_BASE3));
43623c35297Sanish 	prom_printf(" BASE 4      = [0x%x]\n",
43723c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_BASE4));
43823c35297Sanish 	prom_printf(" BASE 5      = [0x%x]\n",
43923c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_BASE5));
44023c35297Sanish 	prom_printf(" Cardbus CIS = [0x%x]\n",
44123c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_CIS));
44223c35297Sanish 	prom_printf(" Sub VID     = [0x%x]\n",
44323c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
44423c35297Sanish 	prom_printf(" Sub SID     = [0x%x]\n",
44523c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
44623c35297Sanish 	prom_printf(" ROM         = [0x%x]\n",
44723c35297Sanish 	    pci_config_get32(config_handle, PCI_CONF_ROM));
44823c35297Sanish 	prom_printf(" I Line      = [0x%x]\n",
44923c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_ILINE));
45023c35297Sanish 	prom_printf(" I Pin       = [0x%x]\n",
45123c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_IPIN));
45223c35297Sanish 	prom_printf(" Max Grant   = [0x%x]\n",
45323c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
45423c35297Sanish 	prom_printf(" Max Latent  = [0x%x]\n",
45523c35297Sanish 	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
45623c35297Sanish }
45723c35297Sanish 
45823c35297Sanish static void
pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)45923c35297Sanish pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
46023c35297Sanish {
46123c35297Sanish 	if ((pcicfg_debug & 1) == 0)
46223c35297Sanish 		return;
46323c35297Sanish 	pcicfg_dump_common_config(config_handle);
46423c35297Sanish 
46523c35297Sanish 	prom_printf("........................................\n");
46623c35297Sanish 
46723c35297Sanish 	prom_printf(" Pri Bus     = [0x%x]\n",
46823c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
46923c35297Sanish 	prom_printf(" Sec Bus     = [0x%x]\n",
47023c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
47123c35297Sanish 	prom_printf(" Sub Bus     = [0x%x]\n",
47223c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
47323c35297Sanish 	prom_printf(" Latency     = [0x%x]\n",
47423c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
47523c35297Sanish 	prom_printf(" I/O Base LO = [0x%x]\n",
47623c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
47723c35297Sanish 	prom_printf(" I/O Lim LO  = [0x%x]\n",
47823c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
47923c35297Sanish 	prom_printf(" Sec. Status = [0x%x]\n",
48023c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
48123c35297Sanish 	prom_printf(" Mem Base    = [0x%x]\n",
48223c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
48323c35297Sanish 	prom_printf(" Mem Limit   = [0x%x]\n",
48423c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
48523c35297Sanish 	prom_printf(" PF Mem Base = [0x%x]\n",
48623c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
48723c35297Sanish 	prom_printf(" PF Mem Lim  = [0x%x]\n",
48823c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
48923c35297Sanish 	prom_printf(" PF Base HI  = [0x%x]\n",
49023c35297Sanish 	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
49123c35297Sanish 	prom_printf(" PF Lim  HI  = [0x%x]\n",
49223c35297Sanish 	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
49323c35297Sanish 	prom_printf(" I/O Base HI = [0x%x]\n",
49423c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
49523c35297Sanish 	prom_printf(" I/O Lim HI  = [0x%x]\n",
49623c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
49723c35297Sanish 	prom_printf(" ROM addr    = [0x%x]\n",
49823c35297Sanish 	    pci_config_get32(config_handle, PCI_BCNF_ROM));
49923c35297Sanish 	prom_printf(" Intr Line   = [0x%x]\n",
50023c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
50123c35297Sanish 	prom_printf(" Intr Pin    = [0x%x]\n",
50223c35297Sanish 	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
50323c35297Sanish 	prom_printf(" Bridge Ctrl = [0x%x]\n",
50423c35297Sanish 	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
50523c35297Sanish }
50623c35297Sanish #endif
50723c35297Sanish 
50823c35297Sanish int
_init()50923c35297Sanish _init()
51023c35297Sanish {
51123c35297Sanish 	DEBUG0(" PCI configurator installed\n");
51223c35297Sanish 	mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
51323c35297Sanish 	return (mod_install(&modlinkage));
51423c35297Sanish }
51523c35297Sanish 
51623c35297Sanish int
_fini(void)51723c35297Sanish _fini(void)
51823c35297Sanish {
51923c35297Sanish 	int error;
52023c35297Sanish 
52123c35297Sanish 	error = mod_remove(&modlinkage);
52223c35297Sanish 	if (error != 0) {
52323c35297Sanish 		return (error);
52423c35297Sanish 	}
52523c35297Sanish 	mutex_destroy(&pcicfg_list_mutex);
52623c35297Sanish 	return (0);
52723c35297Sanish }
52823c35297Sanish 
52923c35297Sanish int
_info(struct modinfo * modinfop)53023c35297Sanish _info(struct modinfo *modinfop)
53123c35297Sanish {
53223c35297Sanish 	return (mod_info(&modlinkage, modinfop));
53323c35297Sanish }
53423c35297Sanish 
53523c35297Sanish /*
53623c35297Sanish  * In the following functions ndi_devi_enter() without holding the
53723c35297Sanish  * parent dip is sufficient. This is because  pci dr is driven through
53823c35297Sanish  * opens on the nexus which is in the device tree path above the node
53923c35297Sanish  * being operated on, and implicitly held due to the open.
54023c35297Sanish  */
54123c35297Sanish 
54223c35297Sanish /*
54323c35297Sanish  * This entry point is called to configure a device (and
54423c35297Sanish  * all its children) on the given bus. It is called when
54523c35297Sanish  * a new device is added to the PCI domain.  This routine
54623c35297Sanish  * will create the device tree and program the devices
54723c35297Sanish  * registers.
54823c35297Sanish  */
54923c35297Sanish int
pcicfg_configure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)55026947304SEvan Yan pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
55126947304SEvan Yan     pcicfg_flags_t flags)
55223c35297Sanish {
55323c35297Sanish 	uint_t bus;
55423c35297Sanish 	int len;
55523c35297Sanish 	int func;
55623c35297Sanish 	dev_info_t *attach_point;
55723c35297Sanish 	pci_bus_range_t pci_bus_range;
55823c35297Sanish 	int rv;
5595c734816SRobert Mustacchi 	uint_t highest_bus, visited = 0;
56026947304SEvan Yan 	int ari_mode = B_FALSE;
56126947304SEvan Yan 	int max_function = PCI_MAX_FUNCTIONS;
56226947304SEvan Yan 	int trans_device;
56326947304SEvan Yan 	dev_info_t *new_device;
564c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
56526947304SEvan Yan 
56626947304SEvan Yan 	if (flags == PCICFG_FLAG_ENABLE_ARI)
56726947304SEvan Yan 		return (pcicfg_ari_configure(devi));
56823c35297Sanish 
56923c35297Sanish 	/*
57023c35297Sanish 	 * Start probing at the device specified in "device" on the
57123c35297Sanish 	 * "bus" specified.
57223c35297Sanish 	 */
57323c35297Sanish 	len = sizeof (pci_bus_range_t);
57423c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, 0, "bus-range",
57523c35297Sanish 	    (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
57623c35297Sanish 		DEBUG0("no bus-range property\n");
57723c35297Sanish 		return (PCICFG_FAILURE);
57823c35297Sanish 	}
57923c35297Sanish 
58023c35297Sanish 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
58123c35297Sanish 
58223c35297Sanish 	attach_point = devi;
58323c35297Sanish 
584c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
585c0da6274SZhi-Jun Robin Fu 
586b31f5cf7SDan Cross 	/*
587b31f5cf7SDan Cross 	 * This code may be racing against other code walking the device info
588b31f5cf7SDan Cross 	 * tree, such as `di_copytree` et al.  To avoid deadlock, we must ensure
589b31f5cf7SDan Cross 	 * a strict hierarchical ordering of `ndi_devi_enter` calls that mirrors
590b31f5cf7SDan Cross 	 * the structure of the tree, working from the root towards leaves.
591b31f5cf7SDan Cross 	 * `pcie_fabric_setup`, if called, will call `ddi_walk_devs` which
592b31f5cf7SDan Cross 	 * requires that the parent is locked; therefore, to obey the lock
593b31f5cf7SDan Cross 	 * ordering, we must lock the parent here.
594b31f5cf7SDan Cross 	 */
5953fe80ca4SDan Cross 	ndi_devi_enter(ddi_get_parent(devi));
5963fe80ca4SDan Cross 	ndi_devi_enter(devi);
59726947304SEvan Yan 	for (func = 0; func < max_function; ) {
59823c35297Sanish 
59926947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
60026947304SEvan Yan 			goto next;
60126947304SEvan Yan 
60226947304SEvan Yan 		if (ari_mode)
60326947304SEvan Yan 			trans_device = func >> 3;
60426947304SEvan Yan 		else
60526947304SEvan Yan 			trans_device = device;
60623c35297Sanish 
60723c35297Sanish 		switch (rv = pcicfg_probe_children(attach_point,
608c0da6274SZhi-Jun Robin Fu 		    bus, trans_device, func & 7, &highest_bus,
609c0da6274SZhi-Jun Robin Fu 		    flags, is_pcie)) {
6105af4ae46Sjveta 			case PCICFG_NORESRC:
61123c35297Sanish 			case PCICFG_FAILURE:
61226947304SEvan Yan 				DEBUG2("configure failed: bus [0x%x] device "
61326947304SEvan Yan 				    "[0x%x]\n", bus, trans_device);
61423c35297Sanish 				goto cleanup;
61523c35297Sanish 			case PCICFG_NODEVICE:
61623c35297Sanish 				DEBUG3("no device : bus "
61723c35297Sanish 				    "[0x%x] slot [0x%x] func [0x%x]\n",
61826947304SEvan Yan 				    bus, trans_device, func &7);
61926947304SEvan Yan 
6207f59ab1cSAlan Adamson, SD OSSD 				/*
6217f59ab1cSAlan Adamson, SD OSSD 				 * When walking the list of ARI functions
6227f59ab1cSAlan Adamson, SD OSSD 				 * we don't expect to see a non-present
6237f59ab1cSAlan Adamson, SD OSSD 				 * function, so we will stop walking
6247f59ab1cSAlan Adamson, SD OSSD 				 * the function list.
6257f59ab1cSAlan Adamson, SD OSSD 				 */
6267f59ab1cSAlan Adamson, SD OSSD 				if (ari_mode == B_TRUE)
6277f59ab1cSAlan Adamson, SD OSSD 					break;
6287f59ab1cSAlan Adamson, SD OSSD 
62926947304SEvan Yan 				if (func)
63026947304SEvan Yan 					goto next;
63126947304SEvan Yan 				break;
63223c35297Sanish 			default:
63323c35297Sanish 				DEBUG3("configure: bus => [%d] "
63423c35297Sanish 				    "slot => [%d] func => [%d]\n",
63526947304SEvan Yan 				    bus, trans_device, func & 7);
63623c35297Sanish 			break;
63723c35297Sanish 		}
63823c35297Sanish 
63923c35297Sanish 		if (rv != PCICFG_SUCCESS)
64023c35297Sanish 			break;
64123c35297Sanish 
64223c35297Sanish 		if ((new_device = pcicfg_devi_find(attach_point,
64326947304SEvan Yan 		    trans_device, func & 7)) == NULL) {
64423c35297Sanish 			DEBUG0("Did'nt find device node just created\n");
64523c35297Sanish 			goto cleanup;
64623c35297Sanish 		}
64723c35297Sanish 
64823c35297Sanish 		/*
64923c35297Sanish 		 * Up until now, we have detected a non transparent bridge
65023c35297Sanish 		 * (ntbridge) as a part of the generic probe code and
65123c35297Sanish 		 * configured only one configuration
65223c35297Sanish 		 * header which is the side facing the host bus.
65323c35297Sanish 		 * Now, configure the other side and create children.
65423c35297Sanish 		 *
65523c35297Sanish 		 * In order to make the process simpler, lets load the device
65623c35297Sanish 		 * driver for the non transparent bridge as this is a
65723c35297Sanish 		 * Solaris bundled driver, and use its configuration map
65823c35297Sanish 		 * services rather than programming it here.
65923c35297Sanish 		 * If the driver is not bundled into Solaris, it must be
66023c35297Sanish 		 * first loaded and configured before performing any
66123c35297Sanish 		 * hotplug operations.
66223c35297Sanish 		 *
66323c35297Sanish 		 * This not only makes the code here simpler but also more
66423c35297Sanish 		 * generic.
66523c35297Sanish 		 *
66623c35297Sanish 		 * So here we go.
66723c35297Sanish 		 */
66823c35297Sanish 
66923c35297Sanish 		/*
67023c35297Sanish 		 * check if this is a bridge in nontransparent mode
67123c35297Sanish 		 */
67223c35297Sanish 		if (pcicfg_is_ntbridge(new_device) != DDI_FAILURE) {
67323c35297Sanish 			DEBUG0("pcicfg: Found nontransparent bridge.\n");
67423c35297Sanish 
67526947304SEvan Yan 			rv = pcicfg_configure_ntbridge(new_device, bus,
67626947304SEvan Yan 			    trans_device);
6775af4ae46Sjveta 			if (rv != PCICFG_SUCCESS)
67823c35297Sanish 				goto cleanup;
67923c35297Sanish 		}
68026947304SEvan Yan 
6815c734816SRobert Mustacchi 		/*
6825c734816SRobert Mustacchi 		 * Note that we've successfully gone through and visited at
6835c734816SRobert Mustacchi 		 * least one node.
6845c734816SRobert Mustacchi 		 */
6855c734816SRobert Mustacchi 		visited++;
68626947304SEvan Yan next:
68726947304SEvan Yan 		/*
68826947304SEvan Yan 		 * Determine if ARI Forwarding should be enabled.
68926947304SEvan Yan 		 */
69026947304SEvan Yan 		if (func == 0) {
69126947304SEvan Yan 			if ((pcie_ari_supported(devi)
69226947304SEvan Yan 			    == PCIE_ARI_FORW_SUPPORTED) &&
69326947304SEvan Yan 			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
69426947304SEvan Yan 				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
69526947304SEvan Yan 					(void) ddi_prop_create(DDI_DEV_T_NONE,
69626947304SEvan Yan 					    devi,  DDI_PROP_CANSLEEP,
69726947304SEvan Yan 					    "ari-enabled", NULL, 0);
69826947304SEvan Yan 
69926947304SEvan Yan 					ari_mode = B_TRUE;
70026947304SEvan Yan 					max_function = PCICFG_MAX_ARI_FUNCTION;
70126947304SEvan Yan 				}
70226947304SEvan Yan 			}
70326947304SEvan Yan 		}
70426947304SEvan Yan 		if (ari_mode == B_TRUE) {
70526947304SEvan Yan 			int next_function;
70626947304SEvan Yan 
70726947304SEvan Yan 			DEBUG0("Next Function - ARI Device\n");
70826947304SEvan Yan 			if (pcie_ari_get_next_function(new_device,
70926947304SEvan Yan 			    &next_function) != DDI_SUCCESS)
71026947304SEvan Yan 				goto cleanup;
71126947304SEvan Yan 
71226947304SEvan Yan 			/*
7135c734816SRobert Mustacchi 			 * Check if there are more functions to probe.
71426947304SEvan Yan 			 */
71526947304SEvan Yan 			if (next_function == 0) {
71626947304SEvan Yan 				DEBUG0("Next Function - "
71726947304SEvan Yan 				    "No more ARI Functions\n");
71826947304SEvan Yan 				break;
71926947304SEvan Yan 			}
72026947304SEvan Yan 			func = next_function;
72126947304SEvan Yan 		} else {
72226947304SEvan Yan 			func++;
72326947304SEvan Yan 		}
72426947304SEvan Yan 		DEBUG1("Next Function - %x\n", func);
72523c35297Sanish 	}
72623c35297Sanish 
7275b2c4190SRobert Mustacchi 	/*
7285b2c4190SRobert Mustacchi 	 * At this point we have set up the various dev_info nodes that we
7295b2c4190SRobert Mustacchi 	 * expect to see in the tree and we must re-evaluate the general fabric
7305b2c4190SRobert Mustacchi 	 * settings such as the overall max payload size or the tagging that is
7315b2c4190SRobert Mustacchi 	 * enabled. However, as part the big theory statement in pcie.c, this
7325b2c4190SRobert Mustacchi 	 * can only be performed on a root port; however, that determination
7335b2c4190SRobert Mustacchi 	 * will be made by the fabric scanning logic.
7345b2c4190SRobert Mustacchi 	 */
7355b2c4190SRobert Mustacchi 	if (visited > 0 && is_pcie) {
7365b2c4190SRobert Mustacchi 		pcie_fabric_setup(devi);
7375b2c4190SRobert Mustacchi 	}
7385b2c4190SRobert Mustacchi 
7393fe80ca4SDan Cross 	ndi_devi_exit(devi);
7403fe80ca4SDan Cross 	ndi_devi_exit(ddi_get_parent(devi));
74123c35297Sanish 
7425c734816SRobert Mustacchi 	if (visited == 0)
74323c35297Sanish 		return (PCICFG_FAILURE);	/* probe failed */
74423c35297Sanish 	else
74523c35297Sanish 		return (PCICFG_SUCCESS);
74623c35297Sanish 
74723c35297Sanish cleanup:
74823c35297Sanish 	/*
74923c35297Sanish 	 * Clean up a partially created "probe state" tree.
75023c35297Sanish 	 * There are no resources allocated to the in the
75123c35297Sanish 	 * probe state.
75223c35297Sanish 	 */
75323c35297Sanish 
75423c35297Sanish 	for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
75526947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
75626947304SEvan Yan 			continue;
75726947304SEvan Yan 
75826947304SEvan Yan 		if ((new_device = pcicfg_devi_find(devi, device, func))
75926947304SEvan Yan 		    == NULL) {
76023c35297Sanish 			continue;
76123c35297Sanish 		}
76223c35297Sanish 
76323c35297Sanish 		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
76423c35297Sanish 		    device, func);
76523c35297Sanish 		/*
76623c35297Sanish 		 * If this was a bridge device it will have a
76723c35297Sanish 		 * probe handle - if not, no harm in calling this.
76823c35297Sanish 		 */
76923c35297Sanish 		(void) pcicfg_destroy_phdl(new_device);
770c0da6274SZhi-Jun Robin Fu 		if (is_pcie) {
771c0da6274SZhi-Jun Robin Fu 			/*
772c0da6274SZhi-Jun Robin Fu 			 * free pcie_bus_t for the sub-tree
773c0da6274SZhi-Jun Robin Fu 			 */
774c0da6274SZhi-Jun Robin Fu 			if (ddi_get_child(new_device) != NULL)
775c0da6274SZhi-Jun Robin Fu 				pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
776c0da6274SZhi-Jun Robin Fu 
777c0da6274SZhi-Jun Robin Fu 			pcie_fini_bus(new_device, PCIE_BUS_ALL);
778c0da6274SZhi-Jun Robin Fu 		}
77923c35297Sanish 		/*
78023c35297Sanish 		 * This will free up the node
78123c35297Sanish 		 */
78223c35297Sanish 		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
78323c35297Sanish 	}
7843fe80ca4SDan Cross 	ndi_devi_exit(devi);
7853fe80ca4SDan Cross 	ndi_devi_exit(ddi_get_parent(devi));
78623c35297Sanish 
7875af4ae46Sjveta 	/*
7885af4ae46Sjveta 	 * Use private return codes to help identify issues without debugging
7895af4ae46Sjveta 	 * enabled.  Resource limitations and mis-configurations are
7905af4ae46Sjveta 	 * probably the most likely caue of configuration failures on x86.
7915af4ae46Sjveta 	 * Convert return code back to values expected by the external
7925af4ae46Sjveta 	 * consumer before returning so we will warn only once on the first
7935af4ae46Sjveta 	 * encountered failure.
7945af4ae46Sjveta 	 */
7955af4ae46Sjveta 	if (rv == PCICFG_NORESRC) {
7965af4ae46Sjveta 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7975af4ae46Sjveta 
7985af4ae46Sjveta 		(void) ddi_pathname(devi, path);
7995af4ae46Sjveta 		cmn_err(CE_CONT, "?Not enough PCI resources to "
8005af4ae46Sjveta 		    "configure: %s\n", path);
8015af4ae46Sjveta 
8025af4ae46Sjveta 		kmem_free(path, MAXPATHLEN);
8035af4ae46Sjveta 		rv = PCICFG_FAILURE;
8045af4ae46Sjveta 	}
8055af4ae46Sjveta 
8065af4ae46Sjveta 	return (rv);
80723c35297Sanish }
80823c35297Sanish 
80923c35297Sanish /*
81023c35297Sanish  * configure the child nodes of ntbridge. new_device points to ntbridge itself
81123c35297Sanish  */
81223c35297Sanish /*ARGSUSED*/
81323c35297Sanish static int
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)81423c35297Sanish pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
81523c35297Sanish {
81623c35297Sanish 	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
81723c35297Sanish 	int			devno;
81823c35297Sanish 	dev_info_t		*new_ntbridgechild;
81923c35297Sanish 	ddi_acc_handle_t	config_handle;
82023c35297Sanish 	uint16_t		vid;
82123c35297Sanish 	uint64_t		next_bus;
82223c35297Sanish 	uint64_t		blen;
82323c35297Sanish 	ndi_ra_request_t	req;
82423c35297Sanish 	uint8_t			pcie_device_type = 0;
82523c35297Sanish 
82623c35297Sanish 	/*
82723c35297Sanish 	 * If we need to do indirect config, lets create a property here
82823c35297Sanish 	 * to let the child conf map routine know that it has to
82923c35297Sanish 	 * go through the DDI calls, and not assume the devices are
83023c35297Sanish 	 * mapped directly under the host.
83123c35297Sanish 	 */
83223c35297Sanish 	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
83326947304SEvan Yan 	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) != DDI_SUCCESS) {
83423c35297Sanish 		DEBUG0("Cannot create indirect conf map property.\n");
83523c35297Sanish 		return ((int)PCICFG_FAILURE);
83623c35297Sanish 	}
83723c35297Sanish 
83823c35297Sanish 	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
83923c35297Sanish 		return (PCICFG_FAILURE);
84023c35297Sanish 	/* check if we are PCIe device */
84123c35297Sanish 	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) {
84223c35297Sanish 		DEBUG0("PCIe device detected\n");
84323c35297Sanish 		pcie_device_type = 1;
84423c35297Sanish 	}
84523c35297Sanish 	pci_config_teardown(&config_handle);
84623c35297Sanish 	/* create Bus node properties for ntbridge. */
84723c35297Sanish 	if (pcicfg_set_busnode_props(new_device, pcie_device_type)
84823c35297Sanish 	    != PCICFG_SUCCESS) {
84923c35297Sanish 		DEBUG0("Failed to set busnode props\n");
85023c35297Sanish 		return (rc);
85123c35297Sanish 	}
85223c35297Sanish 
85323c35297Sanish 	/* For now: Lets only support one layer of child */
85423c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
85523c35297Sanish 	req.ra_len = 1;
85626947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(new_device), &req, &next_bus, &blen,
85726947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
85823c35297Sanish 		DEBUG0("ntbridge: Failed to get a bus number\n");
8595af4ae46Sjveta 		return (PCICFG_NORESRC);
86023c35297Sanish 	}
86123c35297Sanish 
86223c35297Sanish 	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
86323c35297Sanish 
86423c35297Sanish 	/*
86523c35297Sanish 	 * Following will change, as we detect more bridges
86623c35297Sanish 	 * on the way.
86723c35297Sanish 	 */
86823c35297Sanish 	bus_range[0] = (int)next_bus;
86923c35297Sanish 	bus_range[1] = (int)next_bus;
87023c35297Sanish 
87126947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, "bus-range",
87226947304SEvan Yan 	    bus_range, 2) != DDI_SUCCESS) {
87323c35297Sanish 		DEBUG0("Cannot set ntbridge bus-range property");
87423c35297Sanish 		return (rc);
87523c35297Sanish 	}
87623c35297Sanish 
87723c35297Sanish 	/*
87823c35297Sanish 	 * The other interface (away from the host) will be
87923c35297Sanish 	 * initialized by the nexus driver when it loads.
88023c35297Sanish 	 * We just have to set the registers and the nexus driver
88123c35297Sanish 	 * figures out the rest.
88223c35297Sanish 	 */
88323c35297Sanish 
88423c35297Sanish 	/*
88523c35297Sanish 	 * finally, lets load and attach the driver
88623c35297Sanish 	 * before configuring children of ntbridge.
88723c35297Sanish 	 */
88823c35297Sanish 	rc = ndi_devi_online(new_device, NDI_ONLINE_ATTACH|NDI_CONFIG);
88923c35297Sanish 	if (rc != NDI_SUCCESS) {
89023c35297Sanish 		cmn_err(CE_WARN,
89123c35297Sanish 		"pcicfg: Fail:cant load nontransparent bridgd driver..\n");
89223c35297Sanish 		rc = PCICFG_FAILURE;
89323c35297Sanish 		return (rc);
89423c35297Sanish 	}
89523c35297Sanish 	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
89623c35297Sanish 
8975af4ae46Sjveta 	/* Now set aside pci resource allocation requests for our children */
89826947304SEvan Yan 	if (pcicfg_ntbridge_allocate_resources(new_device) != PCICFG_SUCCESS) {
89923c35297Sanish 		max_devs = 0;
90023c35297Sanish 		rc = PCICFG_FAILURE;
90123c35297Sanish 	} else
90223c35297Sanish 		max_devs = PCI_MAX_DEVICES;
90323c35297Sanish 
90423c35297Sanish 	/* Probe devices on 2nd bus */
9055af4ae46Sjveta 	rc = PCICFG_SUCCESS;
90623c35297Sanish 	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
90723c35297Sanish 
90823c35297Sanish 		ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
90923c35297Sanish 		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
91023c35297Sanish 
91123c35297Sanish 		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
91223c35297Sanish 		    != DDI_PROP_SUCCESS) {
91323c35297Sanish 			cmn_err(CE_WARN,
91423c35297Sanish 			    "Failed to add conf reg for ntbridge child.\n");
91523c35297Sanish 			(void) ndi_devi_free(new_ntbridgechild);
91623c35297Sanish 			rc = PCICFG_FAILURE;
91723c35297Sanish 			break;
91823c35297Sanish 		}
91923c35297Sanish 
92023c35297Sanish 		if (pci_config_setup(new_ntbridgechild, &config_handle)
92123c35297Sanish 		    != DDI_SUCCESS) {
92223c35297Sanish 			cmn_err(CE_WARN,
92323c35297Sanish 			    "Cannot map ntbridge child %x\n", devno);
92423c35297Sanish 			(void) ndi_devi_free(new_ntbridgechild);
92523c35297Sanish 			rc = PCICFG_FAILURE;
92623c35297Sanish 			break;
92723c35297Sanish 		}
92823c35297Sanish 
92923c35297Sanish 		/*
93023c35297Sanish 		 * See if there is any PCI HW at this location
93123c35297Sanish 		 * by reading the Vendor ID.  If it returns with 0xffff
93223c35297Sanish 		 * then there is no hardware at this location.
93323c35297Sanish 		 */
93423c35297Sanish 		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
93523c35297Sanish 
93623c35297Sanish 		pci_config_teardown(&config_handle);
93723c35297Sanish 		(void) ndi_devi_free(new_ntbridgechild);
93823c35297Sanish 		if (vid	== 0xffff)
93923c35297Sanish 			continue;
94023c35297Sanish 
94123c35297Sanish 		/* Lets fake attachments points for each child, */
94226947304SEvan Yan 		rc = pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0);
9435af4ae46Sjveta 		if (rc != PCICFG_SUCCESS) {
94423c35297Sanish 			int old_dev = pcicfg_start_devno;
94523c35297Sanish 
94623c35297Sanish 			cmn_err(CE_WARN,
94723c35297Sanish 			    "Error configuring ntbridge child dev=%d\n", devno);
94823c35297Sanish 
94923c35297Sanish 			while (old_dev != devno) {
95023c35297Sanish 				if (pcicfg_ntbridge_unconfigure_child(
95123c35297Sanish 				    new_device, old_dev) == PCICFG_FAILURE)
95226947304SEvan Yan 					cmn_err(CE_WARN, "Unconfig Error "
95326947304SEvan Yan 					    "ntbridge child dev=%d\n", old_dev);
95423c35297Sanish 				old_dev++;
95523c35297Sanish 			}
95623c35297Sanish 			break;
95723c35297Sanish 		}
95823c35297Sanish 	} /* devno loop */
95923c35297Sanish 	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
96023c35297Sanish 
9615af4ae46Sjveta 	if (rc == PCICFG_SUCCESS)
96223c35297Sanish 		rc = pcicfg_ntbridge_configure_done(new_device);
96323c35297Sanish 	else {
96423c35297Sanish 		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
96523c35297Sanish 		uint_t			*bus;
96623c35297Sanish 		int			k;
96723c35297Sanish 
96823c35297Sanish 		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
96926947304SEvan Yan 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, &k)
97026947304SEvan Yan 		    != DDI_PROP_SUCCESS) {
97123c35297Sanish 			DEBUG0("Failed to read bus-range property\n");
97223c35297Sanish 			rc = PCICFG_FAILURE;
97323c35297Sanish 			return (rc);
97423c35297Sanish 		}
97523c35297Sanish 
97623c35297Sanish 		DEBUG2("Need to free bus [%d] range [%d]\n",
97723c35297Sanish 		    bus[0], bus[1] - bus[0] + 1);
97823c35297Sanish 
97926947304SEvan Yan 		if (ndi_ra_free(ddi_get_parent(new_device), (uint64_t)bus[0],
98026947304SEvan Yan 		    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
98126947304SEvan Yan 		    NDI_RA_PASS) != NDI_SUCCESS) {
98223c35297Sanish 			DEBUG0("Failed to free a bus number\n");
98323c35297Sanish 			rc = PCICFG_FAILURE;
9841fb5b786Sprasad 			kmem_free(bus, k);
98523c35297Sanish 			return (rc);
98623c35297Sanish 		}
98723c35297Sanish 
98823c35297Sanish 		/*
98923c35297Sanish 		 * Since no memory allocations are done for non transparent
99023c35297Sanish 		 * bridges (but instead we just set the handle with the
99123c35297Sanish 		 * already allocated memory, we just need to reset the
99223c35297Sanish 		 * following values before calling the destroy_phdl()
99323c35297Sanish 		 * function next, otherwise the it will try to free
99423c35297Sanish 		 * memory allocated as in case of a transparent bridge.
99523c35297Sanish 		 */
99623c35297Sanish 		entry->memory_len = 0;
99723c35297Sanish 		entry->pf_memory_len = 0;
99823c35297Sanish 		entry->io_len = 0;
9991fb5b786Sprasad 		kmem_free(bus, k);
100023c35297Sanish 		/* the following will free hole data. */
100123c35297Sanish 		(void) pcicfg_destroy_phdl(new_device);
100223c35297Sanish 	}
100323c35297Sanish 
100423c35297Sanish 	/*
100523c35297Sanish 	 * Unload driver just in case child configure failed!
100623c35297Sanish 	 */
100723c35297Sanish 	rc1 = ndi_devi_offline(new_device, 0);
100823c35297Sanish 	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
100923c35297Sanish 	if (rc1 != NDI_SUCCESS) {
101023c35297Sanish 		cmn_err(CE_WARN,
101123c35297Sanish 		"pcicfg: cant unload ntbridge driver..children.\n");
101223c35297Sanish 		rc = PCICFG_FAILURE;
101323c35297Sanish 	}
101423c35297Sanish 
101523c35297Sanish 	return (rc);
101623c35297Sanish }
101723c35297Sanish 
101823c35297Sanish static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)101923c35297Sanish pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
102023c35297Sanish {
102123c35297Sanish 	pcicfg_phdl_t		*phdl;
102223c35297Sanish 	ndi_ra_request_t	*mem_request;
102323c35297Sanish 	ndi_ra_request_t	*pf_mem_request;
102423c35297Sanish 	ndi_ra_request_t	*io_request;
102523c35297Sanish 	uint64_t		boundbase, boundlen;
102623c35297Sanish 
102723c35297Sanish 	phdl = pcicfg_find_phdl(dip);
102823c35297Sanish 	ASSERT(phdl);
102923c35297Sanish 
103023c35297Sanish 	mem_request = &phdl->mem_req;
103123c35297Sanish 	pf_mem_request = &phdl->pf_mem_req;
103223c35297Sanish 	io_request  = &phdl->io_req;
103323c35297Sanish 
103423c35297Sanish 	phdl->error = PCICFG_SUCCESS;
103523c35297Sanish 
103623c35297Sanish 	/* Set Memory space handle for ntbridge */
103723c35297Sanish 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
103823c35297Sanish 	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
103923c35297Sanish 		cmn_err(CE_WARN,
104023c35297Sanish 		    "ntbridge: Mem resource information failure\n");
104123c35297Sanish 		phdl->memory_len  = 0;
104223c35297Sanish 		return (PCICFG_FAILURE);
104323c35297Sanish 	}
104423c35297Sanish 	mem_request->ra_boundbase = boundbase;
104523c35297Sanish 	mem_request->ra_boundlen = boundbase + boundlen;
104623c35297Sanish 	mem_request->ra_len = boundlen;
104723c35297Sanish 	mem_request->ra_align_mask =
104823c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
104923c35297Sanish 	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
105023c35297Sanish 
105123c35297Sanish 	/*
105223c35297Sanish 	 * mem_request->ra_len =
105323c35297Sanish 	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
105423c35297Sanish 	 */
105523c35297Sanish 
105623c35297Sanish 	phdl->memory_base = phdl->memory_last = boundbase;
105723c35297Sanish 	phdl->memory_len  = boundlen;
105823c35297Sanish 	phdl->mem_hole.start = phdl->memory_base;
105923c35297Sanish 	phdl->mem_hole.len = mem_request->ra_len;
106023c35297Sanish 	phdl->mem_hole.next = (hole_t *)NULL;
106123c35297Sanish 
106226947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
106323c35297Sanish 	    boundlen, mem_request->ra_len);
106423c35297Sanish 
106523c35297Sanish 	/* Set IO space handle for ntbridge */
106623c35297Sanish 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
106723c35297Sanish 	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
106823c35297Sanish 		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
106923c35297Sanish 		phdl->io_len  = 0;
107023c35297Sanish 		return (PCICFG_FAILURE);
107123c35297Sanish 	}
107223c35297Sanish 	io_request->ra_len = boundlen;
107323c35297Sanish 	io_request->ra_align_mask =
107423c35297Sanish 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
107523c35297Sanish 	io_request->ra_boundbase = boundbase;
107623c35297Sanish 	io_request->ra_boundlen = boundbase + boundlen;
107723c35297Sanish 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
107823c35297Sanish 
107923c35297Sanish 	/*
108023c35297Sanish 	 * io_request->ra_len =
108123c35297Sanish 	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
108223c35297Sanish 	 */
108323c35297Sanish 
108423c35297Sanish 	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
108523c35297Sanish 	phdl->io_len  = (uint32_t)boundlen;
108623c35297Sanish 	phdl->io_hole.start = phdl->io_base;
108723c35297Sanish 	phdl->io_hole.len = io_request->ra_len;
108823c35297Sanish 	phdl->io_hole.next = (hole_t *)NULL;
108923c35297Sanish 
109026947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
109123c35297Sanish 	    boundlen, io_request->ra_len);
109223c35297Sanish 
109323c35297Sanish 	/* Set Prefetchable Memory space handle for ntbridge */
109423c35297Sanish 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
109523c35297Sanish 	    PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
109623c35297Sanish 		cmn_err(CE_WARN,
109723c35297Sanish 		    "ntbridge: PF Mem resource information failure\n");
109823c35297Sanish 		phdl->pf_memory_len  = 0;
109923c35297Sanish 		return (PCICFG_FAILURE);
110023c35297Sanish 	}
110123c35297Sanish 	pf_mem_request->ra_boundbase = boundbase;
110223c35297Sanish 	pf_mem_request->ra_boundlen = boundbase + boundlen;
110323c35297Sanish 	pf_mem_request->ra_len = boundlen;
110423c35297Sanish 	pf_mem_request->ra_align_mask =
110523c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
110623c35297Sanish 	pf_mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
110723c35297Sanish 
110823c35297Sanish 	/*
110923c35297Sanish 	 * pf_mem_request->ra_len =
111023c35297Sanish 	 * PCICFG_ROUND_UP(pf_mem_request->ra_len, PCICFG_MEMGRAN);
111123c35297Sanish 	 */
111223c35297Sanish 
111323c35297Sanish 	phdl->pf_memory_base = phdl->pf_memory_last = boundbase;
111423c35297Sanish 	phdl->pf_memory_len  = boundlen;
111523c35297Sanish 	phdl->pf_mem_hole.start = phdl->pf_memory_base;
111623c35297Sanish 	phdl->pf_mem_hole.len = pf_mem_request->ra_len;
111723c35297Sanish 	phdl->pf_mem_hole.next = (hole_t *)NULL;
111823c35297Sanish 
111926947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of PF "
112026947304SEvan Yan 	    "memory\n", boundlen, pf_mem_request->ra_len);
112123c35297Sanish 
112223c35297Sanish 	DEBUG2("MEMORY BASE = [0x%lx] length [0x%lx]\n",
112323c35297Sanish 	    phdl->memory_base, phdl->memory_len);
112423c35297Sanish 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
112523c35297Sanish 	    phdl->io_base, phdl->io_len);
112623c35297Sanish 	DEBUG2("PF MEMORY BASE = [0x%lx] length [0x%lx]\n",
112723c35297Sanish 	    phdl->pf_memory_base, phdl->pf_memory_len);
112823c35297Sanish 
112923c35297Sanish 	return (PCICFG_SUCCESS);
113023c35297Sanish }
113123c35297Sanish 
113223c35297Sanish static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)113323c35297Sanish pcicfg_ntbridge_configure_done(dev_info_t *dip)
113423c35297Sanish {
113523c35297Sanish 	ppb_ranges_t range[PCICFG_RANGE_LEN];
113623c35297Sanish 	pcicfg_phdl_t		*entry;
113723c35297Sanish 	uint_t			len;
113823c35297Sanish 	pci_bus_range_t		bus_range;
113923c35297Sanish 	int			new_bus_range[2];
114023c35297Sanish 
114123c35297Sanish 	DEBUG1("Configuring children for %p\n", dip);
114223c35297Sanish 
114323c35297Sanish 	entry = pcicfg_find_phdl(dip);
114423c35297Sanish 	ASSERT(entry);
114523c35297Sanish 
114626947304SEvan Yan 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
114723c35297Sanish 	range[1].child_high = range[1].parent_high |=
114823c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
114923c35297Sanish 	range[1].child_low = range[1].parent_low = (uint32_t)entry->memory_base;
115023c35297Sanish 
115123c35297Sanish 	range[0].child_high = range[0].parent_high |=
115223c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_IO);
115323c35297Sanish 	range[0].child_low = range[0].parent_low = (uint32_t)entry->io_base;
115423c35297Sanish 
115523c35297Sanish 	range[2].child_high = range[2].parent_high |=
115623c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
115723c35297Sanish 	range[2].child_low = range[2].parent_low =
115823c35297Sanish 	    (uint32_t)entry->pf_memory_base;
115923c35297Sanish 
116023c35297Sanish 	len = sizeof (pci_bus_range_t);
116123c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
116223c35297Sanish 	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
116323c35297Sanish 		DEBUG0("no bus-range property\n");
116423c35297Sanish 		return (PCICFG_FAILURE);
116523c35297Sanish 	}
116623c35297Sanish 
116723c35297Sanish 	new_bus_range[0] = bus_range.lo;	/* primary bus number */
116823c35297Sanish 	if (entry->highest_bus) {	/* secondary bus number */
116923c35297Sanish 		if (entry->highest_bus < bus_range.lo) {
117023c35297Sanish 			cmn_err(CE_WARN,
117123c35297Sanish 			    "ntbridge bus range invalid !(%d,%d)\n",
117223c35297Sanish 			    bus_range.lo, entry->highest_bus);
117323c35297Sanish 			new_bus_range[1] = bus_range.lo + entry->highest_bus;
117423c35297Sanish 		}
117523c35297Sanish 		else
117623c35297Sanish 			new_bus_range[1] = entry->highest_bus;
117723c35297Sanish 	}
117823c35297Sanish 	else
117923c35297Sanish 		new_bus_range[1] = bus_range.hi;
118023c35297Sanish 
118126947304SEvan Yan 	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", new_bus_range[0],
118226947304SEvan Yan 	    new_bus_range[1]);
118323c35297Sanish 
118426947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "bus-range",
118526947304SEvan Yan 	    new_bus_range, 2) != DDI_SUCCESS) {
118623c35297Sanish 		DEBUG0("Failed to set bus-range property");
118723c35297Sanish 		entry->error = PCICFG_FAILURE;
118823c35297Sanish 		return (PCICFG_FAILURE);
118923c35297Sanish 	}
119023c35297Sanish 
119123c35297Sanish #ifdef DEBUG
119223c35297Sanish 	{
119323c35297Sanish 		uint64_t	unused;
119423c35297Sanish 		unused = pcicfg_unused_space(&entry->io_hole, &len);
119523c35297Sanish 		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
119623c35297Sanish 		    unused, len);
119723c35297Sanish 	}
119823c35297Sanish #endif
119923c35297Sanish 
120023c35297Sanish 	range[0].size_low = entry->io_len;
120123c35297Sanish 	if (pcicfg_update_ranges_prop(dip, &range[0])) {
120223c35297Sanish 		DEBUG0("Failed to update ranges (i/o)\n");
120323c35297Sanish 		entry->error = PCICFG_FAILURE;
120423c35297Sanish 		return (PCICFG_FAILURE);
120523c35297Sanish 	}
120623c35297Sanish 
120723c35297Sanish #ifdef DEBUG
120823c35297Sanish 	{
120923c35297Sanish 		uint64_t	unused;
121023c35297Sanish 		unused = pcicfg_unused_space(&entry->mem_hole, &len);
121123c35297Sanish 		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
121223c35297Sanish 		    unused, len);
121323c35297Sanish 	}
121423c35297Sanish #endif
121523c35297Sanish 
121623c35297Sanish 	range[1].size_low = entry->memory_len;
121723c35297Sanish 	if (pcicfg_update_ranges_prop(dip, &range[1])) {
121823c35297Sanish 		DEBUG0("Failed to update ranges (memory)\n");
121923c35297Sanish 		entry->error = PCICFG_FAILURE;
122023c35297Sanish 		return (PCICFG_FAILURE);
122123c35297Sanish 	}
122223c35297Sanish 
122323c35297Sanish #ifdef DEBUG
122423c35297Sanish 	{
122523c35297Sanish 		uint64_t	unused;
122623c35297Sanish 		unused = pcicfg_unused_space(&entry->pf_mem_hole, &len);
122723c35297Sanish 		DEBUG2("ntbridge: Unused PF Mem space %llx bytes over"
122823c35297Sanish 		    " %d holes\n", unused, len);
122923c35297Sanish 	}
123023c35297Sanish #endif
123123c35297Sanish 
123223c35297Sanish 	range[2].size_low = entry->pf_memory_len;
123323c35297Sanish 	if (pcicfg_update_ranges_prop(dip, &range[2])) {
123423c35297Sanish 		DEBUG0("Failed to update ranges (PF memory)\n");
123523c35297Sanish 		entry->error = PCICFG_FAILURE;
123623c35297Sanish 		return (PCICFG_FAILURE);
123723c35297Sanish 	}
123823c35297Sanish 
123923c35297Sanish 	return (PCICFG_SUCCESS);
124023c35297Sanish }
124123c35297Sanish 
124223c35297Sanish static int
pcicfg_ntbridge_program_child(dev_info_t * dip)124323c35297Sanish pcicfg_ntbridge_program_child(dev_info_t *dip)
124423c35297Sanish {
124523c35297Sanish 	pcicfg_phdl_t	*entry;
124623c35297Sanish 	int		rc = PCICFG_SUCCESS;
124723c35297Sanish 	dev_info_t	*anode = dip;
124823c35297Sanish 
124926947304SEvan Yan 	/* Find the Hotplug Connection (CN) node */
125026947304SEvan Yan 	while ((anode != NULL) &&
125126947304SEvan Yan 	    (strcmp(ddi_binding_name(anode), "hp_attachment") != 0)) {
125223c35297Sanish 		anode = ddi_get_parent(anode);
125323c35297Sanish 	}
125423c35297Sanish 
125523c35297Sanish 	if (anode == NULL) {
125623c35297Sanish 		DEBUG0("ntbridge child tree not in PROBE state\n");
125723c35297Sanish 		return (PCICFG_FAILURE);
125823c35297Sanish 	}
125923c35297Sanish 	entry = pcicfg_find_phdl(ddi_get_parent(anode));
126023c35297Sanish 	ASSERT(entry);
126123c35297Sanish 
126223c35297Sanish 	if (pcicfg_bridge_assign(dip, entry) == DDI_WALK_TERMINATE) {
126323c35297Sanish 		cmn_err(CE_WARN,
126423c35297Sanish 		    "ntbridge: Error assigning range for child %s\n",
126523c35297Sanish 		    ddi_get_name(dip));
126623c35297Sanish 		rc = PCICFG_FAILURE;
126723c35297Sanish 	}
126823c35297Sanish 	return (rc);
126923c35297Sanish }
127023c35297Sanish 
127123c35297Sanish static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)127223c35297Sanish pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
127323c35297Sanish {
127423c35297Sanish 
127523c35297Sanish 	dev_info_t	*new_ntbridgechild;
127623c35297Sanish 	int		len, bus;
127723c35297Sanish 	uint16_t	vid;
127823c35297Sanish 	ddi_acc_handle_t	config_handle;
127923c35297Sanish 	pci_bus_range_t pci_bus_range;
128023c35297Sanish 
128123c35297Sanish 	len = sizeof (pci_bus_range_t);
128223c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
128323c35297Sanish 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
128423c35297Sanish 		DEBUG0("no bus-range property\n");
128523c35297Sanish 		return (PCICFG_FAILURE);
128623c35297Sanish 	}
128723c35297Sanish 
128823c35297Sanish 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
128923c35297Sanish 
129023c35297Sanish 	ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
129123c35297Sanish 	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
129223c35297Sanish 
129323c35297Sanish 	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
129423c35297Sanish 	    != DDI_PROP_SUCCESS) {
129526947304SEvan Yan 		cmn_err(CE_WARN, "Unconfigure: Failed to add conf reg prop for "
129626947304SEvan Yan 		    "ntbridge child.\n");
129723c35297Sanish 		(void) ndi_devi_free(new_ntbridgechild);
129823c35297Sanish 		return (PCICFG_FAILURE);
129923c35297Sanish 	}
130023c35297Sanish 
130123c35297Sanish 	if (pci_config_setup(new_ntbridgechild, &config_handle)
130223c35297Sanish 	    != DDI_SUCCESS) {
130326947304SEvan Yan 		cmn_err(CE_WARN, "pcicfg: Cannot map ntbridge child %x\n",
130426947304SEvan Yan 		    devno);
130523c35297Sanish 		(void) ndi_devi_free(new_ntbridgechild);
130623c35297Sanish 		return (PCICFG_FAILURE);
130723c35297Sanish 	}
130823c35297Sanish 
130923c35297Sanish 	/*
131023c35297Sanish 	 * See if there is any PCI HW at this location
131123c35297Sanish 	 * by reading the Vendor ID.  If it returns with 0xffff
131223c35297Sanish 	 * then there is no hardware at this location.
131323c35297Sanish 	 */
131423c35297Sanish 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
131523c35297Sanish 
131623c35297Sanish 	pci_config_teardown(&config_handle);
131723c35297Sanish 	(void) ndi_devi_free(new_ntbridgechild);
131823c35297Sanish 	if (vid	== 0xffff)
131923c35297Sanish 		return (PCICFG_NODEVICE);
132023c35297Sanish 
132126947304SEvan Yan 	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
132223c35297Sanish }
132323c35297Sanish 
132423c35297Sanish static uint_t
pcicfg_ntbridge_unconfigure(dev_info_t * dip)132523c35297Sanish pcicfg_ntbridge_unconfigure(dev_info_t *dip)
132623c35297Sanish {
132723c35297Sanish 	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
132823c35297Sanish 	uint_t			*bus;
132923c35297Sanish 	int			k, rc = DDI_FAILURE;
133023c35297Sanish 
133126947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range",
133226947304SEvan Yan 	    (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
133323c35297Sanish 		DEBUG0("ntbridge: Failed to read bus-range property\n");
133423c35297Sanish 		return (rc);
133523c35297Sanish 	}
133623c35297Sanish 
133723c35297Sanish 	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
133823c35297Sanish 	    bus[0], bus[1] - bus[0] + 1);
133923c35297Sanish 
134026947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
134126947304SEvan Yan 	    (uint64_t)(bus[1] - bus[0] + 1),
134223c35297Sanish 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
134323c35297Sanish 		DEBUG0("ntbridge: Failed to free a bus number\n");
134423c35297Sanish 		kmem_free(bus, k);
134523c35297Sanish 		return (rc);
134623c35297Sanish 	}
134723c35297Sanish 
134823c35297Sanish 	/*
134923c35297Sanish 	 * Since our resources will be freed at the parent level,
135023c35297Sanish 	 * just reset these values.
135123c35297Sanish 	 */
135223c35297Sanish 	entry->memory_len = 0;
135323c35297Sanish 	entry->io_len = 0;
135423c35297Sanish 	entry->pf_memory_len = 0;
135523c35297Sanish 
135623c35297Sanish 	kmem_free(bus, k);
135723c35297Sanish 
135823c35297Sanish 	/* the following will also free hole data. */
135923c35297Sanish 	return (pcicfg_destroy_phdl(dip));
136023c35297Sanish 
136123c35297Sanish }
136223c35297Sanish 
136323c35297Sanish static int
pcicfg_is_ntbridge(dev_info_t * dip)136423c35297Sanish pcicfg_is_ntbridge(dev_info_t *dip)
136523c35297Sanish {
136623c35297Sanish 	ddi_acc_handle_t	config_handle;
136723c35297Sanish 	uint8_t		class, subclass;
136823c35297Sanish 	int		rc = DDI_SUCCESS;
136923c35297Sanish 
137023c35297Sanish 	if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
137123c35297Sanish 		cmn_err(CE_WARN,
137223c35297Sanish 		    "pcicfg: cannot map config space, to get map type\n");
137323c35297Sanish 		return (DDI_FAILURE);
137423c35297Sanish 	}
137523c35297Sanish 	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
137623c35297Sanish 	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
137723c35297Sanish 
137823c35297Sanish 	/* check for class=6, subclass=9, for non transparent bridges.  */
137923c35297Sanish 	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
138023c35297Sanish 		rc = DDI_FAILURE;
138123c35297Sanish 
138223c35297Sanish 	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
138323c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_VENID),
138423c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_DEVID),
138523c35297Sanish 	    rc);
138623c35297Sanish 	pci_config_teardown(&config_handle);
138723c35297Sanish 	return (rc);
138823c35297Sanish }
138923c35297Sanish 
139023c35297Sanish static uint_t
pcicfg_ntbridge_child(dev_info_t * dip)139123c35297Sanish pcicfg_ntbridge_child(dev_info_t *dip)
139223c35297Sanish {
139323c35297Sanish 	int		len, val, rc = DDI_FAILURE;
139423c35297Sanish 	dev_info_t	*anode = dip;
139523c35297Sanish 
139623c35297Sanish 	/*
139726947304SEvan Yan 	 * Find the Hotplug Connection (CN) node
139823c35297Sanish 	 */
139923c35297Sanish 	while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
140023c35297Sanish 	    "hp_attachment") != 0)) {
140123c35297Sanish 		anode = ddi_get_parent(anode);
140223c35297Sanish 	}
140323c35297Sanish 
140423c35297Sanish 	if (anode == NULL) {
140523c35297Sanish 		DEBUG0("ntbridge child tree not in PROBE state\n");
140623c35297Sanish 		return (rc);
140723c35297Sanish 	}
140823c35297Sanish 	len = sizeof (int);
140923c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(anode),
141026947304SEvan Yan 	    DDI_PROP_DONTPASS, PCI_DEV_CONF_MAP_PROP, (caddr_t)&val, &len)
141126947304SEvan Yan 	    != DDI_SUCCESS) {
141223c35297Sanish 
141323c35297Sanish 		DEBUG1("ntbridge child: no \"%s\" property\n",
141423c35297Sanish 		    PCI_DEV_CONF_MAP_PROP);
141523c35297Sanish 		return (rc);
141623c35297Sanish 	}
141723c35297Sanish 	DEBUG0("ntbridge child: success\n");
141823c35297Sanish 	return (DDI_SUCCESS);
141923c35297Sanish }
142023c35297Sanish 
142123c35297Sanish static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)142223c35297Sanish pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
142323c35297Sanish     uint64_t *boundlen, uint_t space_type)
142423c35297Sanish {
142523c35297Sanish 	int		length, found = DDI_FAILURE, acount, i, ibridge;
142623c35297Sanish 	pci_regspec_t	*assigned;
142723c35297Sanish 
142823c35297Sanish 	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
142923c35297Sanish 		return (found);
143023c35297Sanish 
143126947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
143226947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &length)
143326947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
143423c35297Sanish 		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
143523c35297Sanish 		return (found);
143623c35297Sanish 	}
143723c35297Sanish 	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
143823c35297Sanish 	    ddi_driver_name(dip));
143923c35297Sanish 
144023c35297Sanish 	acount = length / sizeof (pci_regspec_t);
144123c35297Sanish 
144223c35297Sanish 	for (i = 0; i < acount; i++) {
144326947304SEvan Yan 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
144426947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
144523c35297Sanish 		    (space_type == PCI_BASE_SPACE_MEM)) {
144623c35297Sanish 			found = DDI_SUCCESS;
144723c35297Sanish 			break;
144826947304SEvan Yan 		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
144926947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].io_range_bar_offset) &&
145023c35297Sanish 		    (space_type == PCI_BASE_SPACE_IO)) {
145123c35297Sanish 			found = DDI_SUCCESS;
145223c35297Sanish 			break;
145326947304SEvan Yan 		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
145423c35297Sanish 		    pcicfg_indirect_map_devs[ibridge].
145523c35297Sanish 		    prefetch_mem_range_bar_offset) &&
145623c35297Sanish 		    (space_type == (PCI_BASE_SPACE_MEM |
145723c35297Sanish 		    PCI_BASE_PREF_M))) {
145823c35297Sanish 			found = DDI_SUCCESS;
145923c35297Sanish 			break;
146023c35297Sanish 		}
146123c35297Sanish 	}
146223c35297Sanish 	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
146323c35297Sanish 	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
146423c35297Sanish 
146523c35297Sanish 	if (found == DDI_SUCCESS)  {
146623c35297Sanish 		*boundbase = assigned[i].pci_phys_low;
146723c35297Sanish 		*boundlen = assigned[i].pci_size_low;
146823c35297Sanish 	}
146923c35297Sanish 
147023c35297Sanish 	kmem_free(assigned, length);
147123c35297Sanish 	return (found);
147223c35297Sanish }
147323c35297Sanish 
147423c35297Sanish /*
147523c35297Sanish  * This will turn  resources allocated by pcicfg_configure()
147626947304SEvan Yan  * and remove the device tree from the Hotplug Connection (CN)
147723c35297Sanish  * and below.  The routine assumes the devices have their
147823c35297Sanish  * drivers detached.
147923c35297Sanish  */
148023c35297Sanish int
pcicfg_unconfigure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)148126947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
148226947304SEvan Yan     pcicfg_flags_t flags)
148323c35297Sanish {
148423c35297Sanish 	dev_info_t *child_dip;
148523c35297Sanish 	int func;
148623c35297Sanish 	int i;
148726947304SEvan Yan 	int max_function, trans_device;
1488c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
148926947304SEvan Yan 
149026947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
149126947304SEvan Yan 		max_function = PCICFG_MAX_ARI_FUNCTION;
149226947304SEvan Yan 	else
149326947304SEvan Yan 		max_function = PCI_MAX_FUNCTIONS;
149423c35297Sanish 
149523c35297Sanish 	/*
149623c35297Sanish 	 * Cycle through devices to make sure none are busy.
149723c35297Sanish 	 * If a single device is busy fail the whole unconfigure.
149823c35297Sanish 	 */
1499c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
1500c0da6274SZhi-Jun Robin Fu 
15013fe80ca4SDan Cross 	ndi_devi_enter(devi);
150226947304SEvan Yan 	for (func = 0; func < max_function; func++) {
150326947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
150426947304SEvan Yan 			continue;
150526947304SEvan Yan 
150626947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
150726947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
150826947304SEvan Yan 		else
150926947304SEvan Yan 			trans_device = device;
151026947304SEvan Yan 
151126947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device,
151226947304SEvan Yan 		    func & 7)) == NULL)
151323c35297Sanish 			continue;
151423c35297Sanish 
151523c35297Sanish 		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
151623c35297Sanish 			continue;
151726947304SEvan Yan 
151823c35297Sanish 		/*
151923c35297Sanish 		 * Device function is busy. Before returning we have to
152023c35297Sanish 		 * put all functions back online which were taken
152123c35297Sanish 		 * offline during the process.
152223c35297Sanish 		 */
152326947304SEvan Yan 		DEBUG2("Device [0x%x] function [0x%x] is busy\n",
152426947304SEvan Yan 		    trans_device, func & 7);
152526947304SEvan Yan 		/*
152626947304SEvan Yan 		 * If we are only asked to offline one specific function,
152726947304SEvan Yan 		 * and that fails, we just simply return.
152826947304SEvan Yan 		 */
152926947304SEvan Yan 		if (function != PCICFG_ALL_FUNC)
153026947304SEvan Yan 			return (PCICFG_FAILURE);
153126947304SEvan Yan 
153223c35297Sanish 		for (i = 0; i < func; i++) {
153326947304SEvan Yan 			if (max_function == PCICFG_MAX_ARI_FUNCTION)
153426947304SEvan Yan 				trans_device = i >> 3;
153526947304SEvan Yan 
153626947304SEvan Yan 			if ((child_dip = pcicfg_devi_find(devi, trans_device,
153726947304SEvan Yan 			    i & 7)) == NULL) {
153826947304SEvan Yan 				DEBUG0("No more devices to put back "
153926947304SEvan Yan 				    "on line!!\n");
154023c35297Sanish 				/*
154123c35297Sanish 				 * Made it through all functions
154223c35297Sanish 				 */
154323c35297Sanish 				continue;
154423c35297Sanish 			}
154526947304SEvan Yan 			if (ndi_devi_online(child_dip, NDI_CONFIG)
154626947304SEvan Yan 			    != NDI_SUCCESS) {
154723c35297Sanish 				DEBUG0("Failed to put back devices state\n");
1548c0da6274SZhi-Jun Robin Fu 				goto fail;
154923c35297Sanish 			}
155023c35297Sanish 		}
1551c0da6274SZhi-Jun Robin Fu 		goto fail;
155223c35297Sanish 	}
155323c35297Sanish 
155423c35297Sanish 	/*
155526947304SEvan Yan 	 * Now, tear down all devinfo nodes for this Connector.
155623c35297Sanish 	 */
155726947304SEvan Yan 	for (func = 0; func < max_function; func++) {
155826947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
155926947304SEvan Yan 			continue;
156026947304SEvan Yan 
156126947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
156226947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
156326947304SEvan Yan 		else
156426947304SEvan Yan 			trans_device = device;
156526947304SEvan Yan 
156626947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device, func & 7))
156726947304SEvan Yan 		    == NULL) {
156826947304SEvan Yan 			DEBUG2("No device at %x,%x\n", trans_device, func & 7);
156923c35297Sanish 			continue;
157023c35297Sanish 		}
157123c35297Sanish 
157223c35297Sanish 		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
157326947304SEvan Yan 		    trans_device, func & 7);
157423c35297Sanish 
157523c35297Sanish 		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
157623c35297Sanish 			if (pcicfg_ntbridge_unconfigure(child_dip) !=
157723c35297Sanish 			    PCICFG_SUCCESS) {
157823c35297Sanish 				cmn_err(CE_WARN,
157923c35297Sanish 				    "ntbridge: unconfigure failed\n");
1580c0da6274SZhi-Jun Robin Fu 				goto fail;
158123c35297Sanish 			}
158223c35297Sanish 
1583c0da6274SZhi-Jun Robin Fu 		if (pcicfg_teardown_device(child_dip, flags, is_pcie)
158426947304SEvan Yan 		    != PCICFG_SUCCESS) {
158523c35297Sanish 			DEBUG2("Failed to tear down device [0x%x]"
158626947304SEvan Yan 			    "function [0x%x]\n", trans_device, func & 7);
1587c0da6274SZhi-Jun Robin Fu 			goto fail;
158823c35297Sanish 		}
158923c35297Sanish 	}
159026947304SEvan Yan 
159126947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
159226947304SEvan Yan 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
159326947304SEvan Yan 		(void) pcie_ari_disable(devi);
159426947304SEvan Yan 	}
159526947304SEvan Yan 
15963fe80ca4SDan Cross 	ndi_devi_exit(devi);
159723c35297Sanish 	return (PCICFG_SUCCESS);
1598c0da6274SZhi-Jun Robin Fu 
1599c0da6274SZhi-Jun Robin Fu fail:
16003fe80ca4SDan Cross 	ndi_devi_exit(devi);
1601c0da6274SZhi-Jun Robin Fu 	return (PCICFG_FAILURE);
160223c35297Sanish }
160323c35297Sanish 
160423c35297Sanish static int
pcicfg_teardown_device(dev_info_t * dip,pcicfg_flags_t flags,boolean_t is_pcie)1605c0da6274SZhi-Jun Robin Fu pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
160623c35297Sanish {
160723c35297Sanish 	ddi_acc_handle_t	handle;
1608ffb64830SJordan Paige Hendricks 	int			ret;
160923c35297Sanish 
161023c35297Sanish 	/*
161123c35297Sanish 	 * Free up resources associated with 'dip'
161223c35297Sanish 	 */
161326947304SEvan Yan 	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
161423c35297Sanish 		DEBUG0("Failed to free resources\n");
161523c35297Sanish 		return (PCICFG_FAILURE);
161623c35297Sanish 	}
161723c35297Sanish 
161823c35297Sanish 	/*
161923c35297Sanish 	 * disable the device
162023c35297Sanish 	 */
1621ffb64830SJordan Paige Hendricks 
1622ffb64830SJordan Paige Hendricks 	ret = pcicfg_config_setup(dip, &handle);
1623ffb64830SJordan Paige Hendricks 	if (ret == PCICFG_SUCCESS) {
162423c35297Sanish 		pcicfg_device_off(handle);
162523c35297Sanish 		pcicfg_config_teardown(&handle);
1626ffb64830SJordan Paige Hendricks 	} else if (ret != PCICFG_NODEVICE) {
1627ffb64830SJordan Paige Hendricks 		/*
1628ffb64830SJordan Paige Hendricks 		 * It is possible the device no longer exists -- for instance,
1629ffb64830SJordan Paige Hendricks 		 * if the device has been pulled from a hotpluggable slot on the
1630ffb64830SJordan Paige Hendricks 		 * system. In this case, do not fail the teardown, though there
1631ffb64830SJordan Paige Hendricks 		 * is less to clean up.
1632ffb64830SJordan Paige Hendricks 		 */
1633ffb64830SJordan Paige Hendricks 		return (PCICFG_FAILURE);
1634ffb64830SJordan Paige Hendricks 	}
163523c35297Sanish 
1636c0da6274SZhi-Jun Robin Fu 	if (is_pcie) {
1637c0da6274SZhi-Jun Robin Fu 		/*
1638c0da6274SZhi-Jun Robin Fu 		 * free pcie_bus_t for the sub-tree
1639c0da6274SZhi-Jun Robin Fu 		 */
1640c0da6274SZhi-Jun Robin Fu 		if (ddi_get_child(dip) != NULL)
1641c0da6274SZhi-Jun Robin Fu 			pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
1642c0da6274SZhi-Jun Robin Fu 
1643c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(dip, PCIE_BUS_ALL);
1644c0da6274SZhi-Jun Robin Fu 	}
1645c0da6274SZhi-Jun Robin Fu 
164623c35297Sanish 	/*
164723c35297Sanish 	 * The framework provides this routine which can
164823c35297Sanish 	 * tear down a sub-tree.
164923c35297Sanish 	 */
165023c35297Sanish 	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
165123c35297Sanish 		DEBUG0("Failed to offline and remove node\n");
165223c35297Sanish 		return (PCICFG_FAILURE);
165323c35297Sanish 	}
165423c35297Sanish 
165523c35297Sanish 	return (PCICFG_SUCCESS);
165623c35297Sanish }
165723c35297Sanish 
165823c35297Sanish /*
165923c35297Sanish  * BEGIN GENERIC SUPPORT ROUTINES
166023c35297Sanish  */
166123c35297Sanish static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)166223c35297Sanish pcicfg_find_phdl(dev_info_t *dip)
166323c35297Sanish {
166423c35297Sanish 	pcicfg_phdl_t *entry;
166523c35297Sanish 	mutex_enter(&pcicfg_list_mutex);
166623c35297Sanish 	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
166723c35297Sanish 		if (entry->dip == dip) {
166823c35297Sanish 			mutex_exit(&pcicfg_list_mutex);
166923c35297Sanish 			return (entry);
167023c35297Sanish 		}
167123c35297Sanish 	}
167223c35297Sanish 	mutex_exit(&pcicfg_list_mutex);
167323c35297Sanish 
167423c35297Sanish 	/*
167523c35297Sanish 	 * Did'nt find entry - create one
167623c35297Sanish 	 */
167723c35297Sanish 	return (pcicfg_create_phdl(dip));
167823c35297Sanish }
167923c35297Sanish 
168023c35297Sanish static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)168123c35297Sanish pcicfg_create_phdl(dev_info_t *dip)
168223c35297Sanish {
168323c35297Sanish 	pcicfg_phdl_t *new;
168423c35297Sanish 
168526947304SEvan Yan 	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), KM_SLEEP);
168623c35297Sanish 
168723c35297Sanish 	new->dip = dip;
168823c35297Sanish 	mutex_enter(&pcicfg_list_mutex);
168923c35297Sanish 	new->next = pcicfg_phdl_list;
169023c35297Sanish 	pcicfg_phdl_list = new;
169123c35297Sanish 	mutex_exit(&pcicfg_list_mutex);
169223c35297Sanish 
169323c35297Sanish 	return (new);
169423c35297Sanish }
169523c35297Sanish 
169623c35297Sanish static int
pcicfg_destroy_phdl(dev_info_t * dip)169723c35297Sanish pcicfg_destroy_phdl(dev_info_t *dip)
169823c35297Sanish {
169923c35297Sanish 	pcicfg_phdl_t *entry;
170023c35297Sanish 	pcicfg_phdl_t *follow = NULL;
170123c35297Sanish 
170223c35297Sanish 	mutex_enter(&pcicfg_list_mutex);
170323c35297Sanish 	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
170423c35297Sanish 	    entry = entry->next) {
170523c35297Sanish 		if (entry->dip == dip) {
170623c35297Sanish 			if (entry == pcicfg_phdl_list) {
170723c35297Sanish 				pcicfg_phdl_list = entry->next;
170823c35297Sanish 			} else {
170923c35297Sanish 				follow->next = entry->next;
171023c35297Sanish 			}
171123c35297Sanish 			/*
171223c35297Sanish 			 * If this entry has any allocated memory
171323c35297Sanish 			 * or IO space associated with it, that
171423c35297Sanish 			 * must be freed up.
171523c35297Sanish 			 */
171623c35297Sanish 			if (entry->memory_len > 0) {
171723c35297Sanish 				(void) ndi_ra_free(ddi_get_parent(dip),
171826947304SEvan Yan 				    entry->memory_base, entry->memory_len,
171923c35297Sanish 				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
172023c35297Sanish 			}
172123c35297Sanish 			pcicfg_free_hole(&entry->mem_hole);
172223c35297Sanish 
172323c35297Sanish 			if (entry->io_len > 0) {
172423c35297Sanish 				(void) ndi_ra_free(ddi_get_parent(dip),
172526947304SEvan Yan 				    entry->io_base, entry->io_len,
172623c35297Sanish 				    NDI_RA_TYPE_IO, NDI_RA_PASS);
172723c35297Sanish 			}
172823c35297Sanish 			pcicfg_free_hole(&entry->io_hole);
172923c35297Sanish 
173023c35297Sanish 			if (entry->pf_memory_len > 0) {
173123c35297Sanish 				(void) ndi_ra_free(ddi_get_parent(dip),
173226947304SEvan Yan 				    entry->pf_memory_base, entry->pf_memory_len,
173326947304SEvan Yan 				    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
173423c35297Sanish 			}
173523c35297Sanish 			pcicfg_free_hole(&entry->pf_mem_hole);
173623c35297Sanish 
173723c35297Sanish 			/*
173823c35297Sanish 			 * Destroy this entry
173923c35297Sanish 			 */
174023c35297Sanish 			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
174123c35297Sanish 			mutex_exit(&pcicfg_list_mutex);
174223c35297Sanish 			return (PCICFG_SUCCESS);
174323c35297Sanish 		}
174423c35297Sanish 	}
174523c35297Sanish 	mutex_exit(&pcicfg_list_mutex);
174623c35297Sanish 	/*
174723c35297Sanish 	 * Did'nt find the entry
174823c35297Sanish 	 */
174923c35297Sanish 	return (PCICFG_FAILURE);
175023c35297Sanish }
175123c35297Sanish 
175223c35297Sanish static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)175323c35297Sanish pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
175423c35297Sanish {
175523c35297Sanish 	ddi_acc_handle_t handle;
175623c35297Sanish 	pci_regspec_t *reg;
175723c35297Sanish 	int length;
175823c35297Sanish 	int rcount;
175923c35297Sanish 	int i;
176023c35297Sanish 	int offset;
176123c35297Sanish 	uint64_t mem_answer;
176223c35297Sanish 	uint32_t io_answer;
176323c35297Sanish 	uint8_t header_type;
176423c35297Sanish 	ppb_ranges_t range[PCICFG_RANGE_LEN];
176523c35297Sanish 	int bus_range[2];
176623c35297Sanish 	uint64_t mem_residual;
176723c35297Sanish 	uint64_t pf_mem_residual;
176823c35297Sanish 	uint64_t io_residual;
176923c35297Sanish 
177023c35297Sanish 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
177123c35297Sanish 
177226947304SEvan Yan 	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
177323c35297Sanish 
177423c35297Sanish 	entry->error = PCICFG_SUCCESS;
177523c35297Sanish 
177623c35297Sanish 	if (entry == NULL) {
177723c35297Sanish 		DEBUG0("Failed to get entry\n");
177823c35297Sanish 		entry->error = PCICFG_FAILURE;
177923c35297Sanish 		return (DDI_WALK_TERMINATE);
178023c35297Sanish 	}
178123c35297Sanish 
178226947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
178323c35297Sanish 		DEBUG0("Failed to map config space!\n");
178423c35297Sanish 		entry->error = PCICFG_FAILURE;
178523c35297Sanish 		return (DDI_WALK_TERMINATE);
178623c35297Sanish 	}
178723c35297Sanish 
178823c35297Sanish 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
178923c35297Sanish 
179023c35297Sanish 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
179123c35297Sanish 
179226947304SEvan Yan 		bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
179323c35297Sanish 
179423c35297Sanish 		(void) pcicfg_setup_bridge(entry, handle);
179523c35297Sanish 
179623c35297Sanish 		range[0].child_high = range[0].parent_high |=
179723c35297Sanish 		    (PCI_REG_REL_M | PCI_ADDR_IO);
179826947304SEvan Yan 		range[0].child_low = range[0].parent_low = entry->io_last;
179923c35297Sanish 		range[1].child_high = range[1].parent_high |=
180023c35297Sanish 		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
180123c35297Sanish 		range[1].child_low = range[1].parent_low =
180223c35297Sanish 		    entry->memory_last;
180323c35297Sanish 		range[2].child_high = range[2].parent_high |=
180423c35297Sanish 		    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
180523c35297Sanish 		range[2].child_low = range[2].parent_low =
180623c35297Sanish 		    entry->pf_memory_last;
180723c35297Sanish 
18083fe80ca4SDan Cross 		ndi_devi_enter(dip);
180923c35297Sanish 		ddi_walk_devs(ddi_get_child(dip),
181023c35297Sanish 		    pcicfg_bridge_assign, (void *)entry);
18113fe80ca4SDan Cross 		ndi_devi_exit(dip);
181223c35297Sanish 
181323c35297Sanish 		(void) pcicfg_update_bridge(entry, handle);
181423c35297Sanish 
181523c35297Sanish 		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
181623c35297Sanish 		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
181723c35297Sanish 
181823c35297Sanish 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
181923c35297Sanish 		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
182023c35297Sanish 			DEBUG0("Failed to set bus-range property");
182123c35297Sanish 			entry->error = PCICFG_FAILURE;
18221fb5b786Sprasad 			(void) pcicfg_config_teardown(&handle);
182323c35297Sanish 			return (DDI_WALK_TERMINATE);
182423c35297Sanish 		}
182523c35297Sanish 
182623c35297Sanish 		/*
182723c35297Sanish 		 * Put back memory and I/O space not allocated
182823c35297Sanish 		 * under the bridge.
182923c35297Sanish 		 */
183023c35297Sanish 		mem_residual = entry->memory_len -
183123c35297Sanish 		    (entry->memory_last - entry->memory_base);
183223c35297Sanish 		if (mem_residual > 0) {
183323c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(dip),
183426947304SEvan Yan 			    entry->memory_last, mem_residual,
183523c35297Sanish 			    NDI_RA_TYPE_MEM, NDI_RA_PASS);
183623c35297Sanish 		}
183723c35297Sanish 
183826947304SEvan Yan 		io_residual = entry->io_len - (entry->io_last - entry->io_base);
183923c35297Sanish 		if (io_residual > 0) {
184026947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(dip), entry->io_last,
184126947304SEvan Yan 			    io_residual, NDI_RA_TYPE_IO, NDI_RA_PASS);
184223c35297Sanish 		}
184323c35297Sanish 
184423c35297Sanish 		pf_mem_residual = entry->pf_memory_len -
184523c35297Sanish 		    (entry->pf_memory_last - entry->pf_memory_base);
184623c35297Sanish 		if (pf_mem_residual > 0) {
184723c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(dip),
184826947304SEvan Yan 			    entry->pf_memory_last, pf_mem_residual,
184923c35297Sanish 			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
185023c35297Sanish 		}
185123c35297Sanish 
185223c35297Sanish 		if (entry->io_len > 0) {
185323c35297Sanish 			range[0].size_low = entry->io_last - entry->io_base;
185423c35297Sanish 			if (pcicfg_update_ranges_prop(dip, &range[0])) {
185523c35297Sanish 				DEBUG0("Failed to update ranges (i/o)\n");
185623c35297Sanish 				entry->error = PCICFG_FAILURE;
18571fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
185823c35297Sanish 				return (DDI_WALK_TERMINATE);
185923c35297Sanish 			}
186023c35297Sanish 		}
186123c35297Sanish 		if (entry->memory_len > 0) {
186223c35297Sanish 			range[1].size_low =
186323c35297Sanish 			    entry->memory_last - entry->memory_base;
186423c35297Sanish 			if (pcicfg_update_ranges_prop(dip, &range[1])) {
186523c35297Sanish 				DEBUG0("Failed to update ranges (memory)\n");
186623c35297Sanish 				entry->error = PCICFG_FAILURE;
18671fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
186823c35297Sanish 				return (DDI_WALK_TERMINATE);
186923c35297Sanish 			}
187023c35297Sanish 		}
187123c35297Sanish 		if (entry->pf_memory_len > 0) {
187223c35297Sanish 			range[2].size_low =
187323c35297Sanish 			    entry->pf_memory_last - entry->pf_memory_base;
187423c35297Sanish 			if (pcicfg_update_ranges_prop(dip, &range[2])) {
187523c35297Sanish 				DEBUG0("Failed to update ranges (PF memory)\n");
187623c35297Sanish 				entry->error = PCICFG_FAILURE;
18771fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
187823c35297Sanish 				return (DDI_WALK_TERMINATE);
187923c35297Sanish 			}
188023c35297Sanish 		}
188123c35297Sanish 
188223c35297Sanish 		(void) pcicfg_device_on(handle);
188323c35297Sanish 
188423c35297Sanish 		PCICFG_DUMP_BRIDGE_CONFIG(handle);
188523c35297Sanish 
18861fb5b786Sprasad 		(void) pcicfg_config_teardown(&handle);
18871fb5b786Sprasad 
188823c35297Sanish 		return (DDI_WALK_PRUNECHILD);
188923c35297Sanish 	}
189023c35297Sanish 
189123c35297Sanish 	/*
189223c35297Sanish 	 * If there is an interrupt pin set program
189323c35297Sanish 	 * interrupt line with default values.
189423c35297Sanish 	 */
189523c35297Sanish 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
189623c35297Sanish 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
189723c35297Sanish 	}
189823c35297Sanish 
189923c35297Sanish 	/*
190023c35297Sanish 	 * A single device (under a bridge).
190123c35297Sanish 	 * For each "reg" property with a length, allocate memory
190223c35297Sanish 	 * and program the base registers.
190323c35297Sanish 	 */
190426947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
190526947304SEvan Yan 	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
190623c35297Sanish 		DEBUG0("Failed to read reg property\n");
190723c35297Sanish 		entry->error = PCICFG_FAILURE;
19081fb5b786Sprasad 		(void) pcicfg_config_teardown(&handle);
190923c35297Sanish 		return (DDI_WALK_TERMINATE);
191023c35297Sanish 	}
191123c35297Sanish 
191223c35297Sanish 	rcount = length / sizeof (pci_regspec_t);
191323c35297Sanish 	offset = PCI_CONF_BASE0;
191423c35297Sanish 	for (i = 0; i < rcount; i++) {
191526947304SEvan Yan 		if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
191623c35297Sanish 
191723c35297Sanish 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
191823c35297Sanish 
191923c35297Sanish 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
192023c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
192123c35297Sanish 
192223c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
192323c35297Sanish 					/* allocate prefetchable memory */
192423c35297Sanish 					pcicfg_get_pf_mem(entry,
192523c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
192623c35297Sanish 				} else { /* get non prefetchable memory */
192723c35297Sanish 					pcicfg_get_mem(entry,
192823c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
192923c35297Sanish 				}
193023c35297Sanish 				pci_config_put64(handle, offset, mem_answer);
193123c35297Sanish 				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
193226947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
193323c35297Sanish 				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
193423c35297Sanish 				    offset + 4,
193523c35297Sanish 				    pci_config_get32(handle, offset + 4));
193623c35297Sanish 
193723c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
193823c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(mem_answer);
193926947304SEvan Yan 				reg[i].pci_phys_mid = PCICFG_HIADDR(mem_answer);
194023c35297Sanish 				break;
194123c35297Sanish 
194223c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
194323c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
194423c35297Sanish 					/* allocate prefetchable memory */
194523c35297Sanish 					pcicfg_get_pf_mem(entry,
194623c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
194723c35297Sanish 				} else {
194823c35297Sanish 					/* get non prefetchable memory */
194923c35297Sanish 					pcicfg_get_mem(entry,
195023c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
195123c35297Sanish 				}
195223c35297Sanish 
195326947304SEvan Yan 				pci_config_put32(handle, offset,
195426947304SEvan Yan 				    (uint32_t)mem_answer);
195523c35297Sanish 
195623c35297Sanish 				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
195726947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
195823c35297Sanish 
195923c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
196023c35297Sanish 				reg[i].pci_phys_low = (uint32_t)mem_answer;
196123c35297Sanish 
196223c35297Sanish 				break;
196323c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
196423c35297Sanish 				/* allocate I/O space from the allocator */
196523c35297Sanish 
196626947304SEvan Yan 				(void) pcicfg_get_io(entry, reg[i].pci_size_low,
196726947304SEvan Yan 				    &io_answer);
196823c35297Sanish 				pci_config_put32(handle, offset, io_answer);
196923c35297Sanish 
197023c35297Sanish 				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
197126947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
197223c35297Sanish 
197323c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
197423c35297Sanish 				reg[i].pci_phys_low = io_answer;
197523c35297Sanish 
197623c35297Sanish 				break;
197723c35297Sanish 			default:
197823c35297Sanish 				DEBUG0("Unknown register type\n");
197923c35297Sanish 				kmem_free(reg, length);
198023c35297Sanish 				(void) pcicfg_config_teardown(&handle);
198123c35297Sanish 				entry->error = PCICFG_FAILURE;
198223c35297Sanish 				return (DDI_WALK_TERMINATE);
198323c35297Sanish 			} /* switch */
198423c35297Sanish 
198523c35297Sanish 			/*
198623c35297Sanish 			 * Now that memory locations are assigned,
198723c35297Sanish 			 * update the assigned address property.
198823c35297Sanish 			 */
198926947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip, &reg[i])
199026947304SEvan Yan 			    != PCICFG_SUCCESS) {
199123c35297Sanish 				kmem_free(reg, length);
199223c35297Sanish 				(void) pcicfg_config_teardown(&handle);
199323c35297Sanish 				entry->error = PCICFG_FAILURE;
199423c35297Sanish 				return (DDI_WALK_TERMINATE);
199523c35297Sanish 			}
199623c35297Sanish 		}
199723c35297Sanish 	}
199823c35297Sanish 	(void) pcicfg_device_on(handle);
199923c35297Sanish 
200023c35297Sanish 	PCICFG_DUMP_DEVICE_CONFIG(handle);
200123c35297Sanish 
200223c35297Sanish 	(void) pcicfg_config_teardown(&handle);
200323c35297Sanish 	kmem_free((caddr_t)reg, length);
200423c35297Sanish 	return (DDI_WALK_CONTINUE);
200523c35297Sanish }
200623c35297Sanish 
200723c35297Sanish static int
pcicfg_device_assign(dev_info_t * dip)200823c35297Sanish pcicfg_device_assign(dev_info_t *dip)
200923c35297Sanish {
201023c35297Sanish 	ddi_acc_handle_t	handle;
201123c35297Sanish 	pci_regspec_t		*reg;
201223c35297Sanish 	int			length;
201323c35297Sanish 	int			rcount;
201423c35297Sanish 	int			i;
201523c35297Sanish 	int			offset;
201623c35297Sanish 	ndi_ra_request_t	request;
201723c35297Sanish 	uint64_t		answer;
201823c35297Sanish 	uint64_t		alen;
201923c35297Sanish 
202023c35297Sanish 	DEBUG1("%llx now under configuration\n", dip);
202123c35297Sanish 
202223c35297Sanish 	/* request.ra_len = PCICFG_ROUND_UP(request.ra_len, PCICFG_IOGRAN); */
202323c35297Sanish 	if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
202423c35297Sanish 
202523c35297Sanish 		return (pcicfg_ntbridge_program_child(dip));
202623c35297Sanish 	}
202723c35297Sanish 	/*
202823c35297Sanish 	 * XXX Failure here should be noted
202923c35297Sanish 	 */
203026947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
203126947304SEvan Yan 	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
203223c35297Sanish 		DEBUG0("Failed to read reg property\n");
203323c35297Sanish 		return (PCICFG_FAILURE);
203423c35297Sanish 	}
203523c35297Sanish 
203623c35297Sanish 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
203723c35297Sanish 		DEBUG0("Failed to map config space!\n");
20381fb5b786Sprasad 		kmem_free(reg, length);
203923c35297Sanish 		return (PCICFG_FAILURE);
204023c35297Sanish 	}
204123c35297Sanish 
204223c35297Sanish 	/*
204323c35297Sanish 	 * A single device
204423c35297Sanish 	 *
204523c35297Sanish 	 * For each "reg" property with a length, allocate memory
204623c35297Sanish 	 * and program the base registers.
204723c35297Sanish 	 */
204823c35297Sanish 
204923c35297Sanish 	/*
205023c35297Sanish 	 * If there is an interrupt pin set program
205123c35297Sanish 	 * interrupt line with default values.
205223c35297Sanish 	 */
205323c35297Sanish 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
205423c35297Sanish 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
205523c35297Sanish 	}
205623c35297Sanish 
205723c35297Sanish 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
205823c35297Sanish 
205923c35297Sanish 	/*
206023c35297Sanish 	 * Note: Both non-prefetchable and prefetchable memory space
206123c35297Sanish 	 * allocations are made within 32bit space. Currently, BIOSs
206223c35297Sanish 	 * allocate device memory for PCI devices within the 32bit space
206323c35297Sanish 	 * so this will not be a problem.
206423c35297Sanish 	 */
206523c35297Sanish 	request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED;
206623c35297Sanish 	request.ra_boundbase = 0;
206723c35297Sanish 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
206823c35297Sanish 
206923c35297Sanish 	rcount = length / sizeof (pci_regspec_t);
207023c35297Sanish 	offset = PCI_CONF_BASE0;
207123c35297Sanish 	for (i = 0; i < rcount; i++) {
207223c35297Sanish 		char	*mem_type;
207323c35297Sanish 
207426947304SEvan Yan 		if ((reg[i].pci_size_low != 0)|| (reg[i].pci_size_hi != 0)) {
207523c35297Sanish 
207623c35297Sanish 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
207723c35297Sanish 			request.ra_len = reg[i].pci_size_low;
207823c35297Sanish 
207923c35297Sanish 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
208023c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
208123c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
208223c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
208323c35297Sanish 				} else {
208423c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
208523c35297Sanish 				}
208623c35297Sanish 				/* allocate memory space from the allocator */
208726947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
208826947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
208926947304SEvan Yan 				    != NDI_SUCCESS) {
209023c35297Sanish 					DEBUG0("Failed to allocate 64b mem\n");
209123c35297Sanish 					kmem_free(reg, length);
209223c35297Sanish 					(void) pcicfg_config_teardown(&handle);
20935af4ae46Sjveta 					return (PCICFG_NORESRC);
209423c35297Sanish 				}
209523c35297Sanish 				DEBUG3("64 addr = [0x%x.0x%x] len [0x%x]\n",
209623c35297Sanish 				    PCICFG_HIADDR(answer),
209726947304SEvan Yan 				    PCICFG_LOADDR(answer), alen);
209823c35297Sanish 				/* program the low word */
209926947304SEvan Yan 				pci_config_put32(handle, offset,
210026947304SEvan Yan 				    PCICFG_LOADDR(answer));
210123c35297Sanish 				/* program the high word */
210223c35297Sanish 				pci_config_put32(handle, offset + 4,
210323c35297Sanish 				    PCICFG_HIADDR(answer));
210423c35297Sanish 
210523c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
210623c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
210723c35297Sanish 				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
210823c35297Sanish 				/*
210923c35297Sanish 				 * currently support 32b address space
211023c35297Sanish 				 * assignments only.
211123c35297Sanish 				 */
211226947304SEvan Yan 				reg[i].pci_phys_hi ^=
211326947304SEvan Yan 				    PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
211423c35297Sanish 
211523c35297Sanish 				offset += 8;
211623c35297Sanish 				break;
211723c35297Sanish 
211823c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
211923c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M)
212023c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
212123c35297Sanish 				else
212223c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
212323c35297Sanish 				/* allocate memory space from the allocator */
212426947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
212526947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
212626947304SEvan Yan 				    != NDI_SUCCESS) {
212723c35297Sanish 					DEBUG0("Failed to allocate 32b mem\n");
212823c35297Sanish 					kmem_free(reg, length);
212923c35297Sanish 					(void) pcicfg_config_teardown(&handle);
21305af4ae46Sjveta 					return (PCICFG_NORESRC);
213123c35297Sanish 				}
213223c35297Sanish 				DEBUG3("32 addr = [0x%x.0x%x] len [0x%x]\n",
213323c35297Sanish 				    PCICFG_HIADDR(answer),
213423c35297Sanish 				    PCICFG_LOADDR(answer),
213523c35297Sanish 				    alen);
213623c35297Sanish 				/* program the low word */
213726947304SEvan Yan 				pci_config_put32(handle, offset,
213826947304SEvan Yan 				    PCICFG_LOADDR(answer));
213923c35297Sanish 
214023c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
214123c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
214223c35297Sanish 				reg[i].pci_phys_mid = 0;
214323c35297Sanish 
214423c35297Sanish 				offset += 4;
214523c35297Sanish 				break;
214623c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
2147b9abf428Slipeng sang - Sun Microsystems - Beijing China 				/*
2148b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * Try to allocate I/O space. If it fails,
2149b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * continue here instead of returning failure
2150b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * so that the hotplug for drivers that don't
2151b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * use I/O space can succeed, For drivers
2152b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * that need to use I/O space, the hotplug
2153b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * will still fail later during driver attach.
2154b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 */
215526947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
215626947304SEvan Yan 				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
215723c35297Sanish 				    != NDI_SUCCESS) {
215823c35297Sanish 					DEBUG0("Failed to allocate I/O\n");
2159b9abf428Slipeng sang - Sun Microsystems - Beijing China 					continue;
216023c35297Sanish 				}
216123c35297Sanish 				DEBUG3("I/O addr = [0x%x.0x%x] len [0x%x]\n",
216223c35297Sanish 				    PCICFG_HIADDR(answer),
216326947304SEvan Yan 				    PCICFG_LOADDR(answer), alen);
216426947304SEvan Yan 				pci_config_put32(handle, offset,
216526947304SEvan Yan 				    PCICFG_LOADDR(answer));
216623c35297Sanish 
216723c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
216823c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
216923c35297Sanish 
217023c35297Sanish 				offset += 4;
217123c35297Sanish 				break;
217223c35297Sanish 			default:
217323c35297Sanish 				DEBUG0("Unknown register type\n");
217423c35297Sanish 				kmem_free(reg, length);
217523c35297Sanish 				(void) pcicfg_config_teardown(&handle);
217623c35297Sanish 				return (PCICFG_FAILURE);
217723c35297Sanish 			} /* switch */
217823c35297Sanish 
217923c35297Sanish 			/*
218023c35297Sanish 			 * Now that memory locations are assigned,
218123c35297Sanish 			 * update the assigned address property.
218223c35297Sanish 			 */
218323c35297Sanish 
218426947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip, &reg[i])
218526947304SEvan Yan 			    != PCICFG_SUCCESS) {
218623c35297Sanish 				kmem_free(reg, length);
218723c35297Sanish 				(void) pcicfg_config_teardown(&handle);
218823c35297Sanish 				return (PCICFG_FAILURE);
218923c35297Sanish 			}
219023c35297Sanish 		}
219123c35297Sanish 	}
219223c35297Sanish 
219323c35297Sanish 	(void) pcicfg_device_on(handle);
219423c35297Sanish 	kmem_free(reg, length);
219523c35297Sanish 
219623c35297Sanish 	PCICFG_DUMP_DEVICE_CONFIG(handle);
219723c35297Sanish 
219823c35297Sanish 	(void) pcicfg_config_teardown(&handle);
219923c35297Sanish 	return (PCICFG_SUCCESS);
220023c35297Sanish }
220123c35297Sanish 
220226947304SEvan Yan static int
pcicfg_device_assign_readonly(dev_info_t * dip)220326947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip)
220426947304SEvan Yan {
220526947304SEvan Yan 	ddi_acc_handle_t	handle;
220626947304SEvan Yan 	pci_regspec_t		*assigned;
220726947304SEvan Yan 	int			length;
220826947304SEvan Yan 	int			acount;
220926947304SEvan Yan 	int			i;
221026947304SEvan Yan 	ndi_ra_request_t	request;
221126947304SEvan Yan 	uint64_t		answer;
221226947304SEvan Yan 	uint64_t		alen;
221326947304SEvan Yan 
221426947304SEvan Yan 	DEBUG1("%llx now under configuration\n", dip);
221526947304SEvan Yan 
221626947304SEvan Yan 	/*
221726947304SEvan Yan 	 * we don't support ntbridges for readonly probe.
221826947304SEvan Yan 	 */
221926947304SEvan Yan 	if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
222026947304SEvan Yan 		return (PCICFG_FAILURE);
222126947304SEvan Yan 	}
222226947304SEvan Yan 
222326947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
222426947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
222526947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
222626947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
222726947304SEvan Yan 		return (PCICFG_FAILURE);
222826947304SEvan Yan 	}
222926947304SEvan Yan 
223026947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
223126947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
223226947304SEvan Yan 		kmem_free(assigned, length);
223326947304SEvan Yan 		return (PCICFG_FAILURE);
223426947304SEvan Yan 	}
223526947304SEvan Yan 
223626947304SEvan Yan 	/*
223726947304SEvan Yan 	 * If there is an interrupt pin set program
223826947304SEvan Yan 	 * interrupt line with default values.
223926947304SEvan Yan 	 */
224026947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
224126947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
224226947304SEvan Yan 	}
224326947304SEvan Yan 	/*
224426947304SEvan Yan 	 * Note: Both non-prefetchable and prefetchable memory space
224526947304SEvan Yan 	 * allocations are made within 32bit space. Currently, BIOSs
224626947304SEvan Yan 	 * allocate device memory for PCI devices within the 32bit space
224726947304SEvan Yan 	 * so this will not be a problem.
224826947304SEvan Yan 	 */
224926947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
225026947304SEvan Yan 
225126947304SEvan Yan 	request.ra_flags = NDI_RA_ALLOC_SPECIFIED;  /* specified addr */
225226947304SEvan Yan 	request.ra_boundbase = 0;
225326947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
225426947304SEvan Yan 
225526947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
225626947304SEvan Yan 	for (i = 0; i < acount; i++) {
225726947304SEvan Yan 		char	*mem_type;
225826947304SEvan Yan 
225926947304SEvan Yan 		if ((assigned[i].pci_size_low != 0)||
226026947304SEvan Yan 		    (assigned[i].pci_size_hi != 0)) {
226126947304SEvan Yan 
226226947304SEvan Yan 			request.ra_len = assigned[i].pci_size_low;
226326947304SEvan Yan 
226426947304SEvan Yan 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
226526947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
226626947304SEvan Yan 				request.ra_addr = (uint64_t)PCICFG_LADDR(
226726947304SEvan Yan 				    assigned[i].pci_phys_low,
226826947304SEvan Yan 				    assigned[i].pci_phys_mid);
226926947304SEvan Yan 
227026947304SEvan Yan 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M) {
227126947304SEvan Yan 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
227226947304SEvan Yan 				} else {
227326947304SEvan Yan 					mem_type = NDI_RA_TYPE_MEM;
227426947304SEvan Yan 				}
227526947304SEvan Yan 				/* allocate memory space from the allocator */
227626947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
227726947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
227826947304SEvan Yan 				    != NDI_SUCCESS) {
227926947304SEvan Yan 					DEBUG0("Failed to allocate 64b mem\n");
228026947304SEvan Yan 					kmem_free(assigned, length);
228126947304SEvan Yan 					return (PCICFG_NORESRC);
228226947304SEvan Yan 				}
228326947304SEvan Yan 
228426947304SEvan Yan 				break;
228526947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
228626947304SEvan Yan 				request.ra_addr = (uint64_t)
228726947304SEvan Yan 				    assigned[i].pci_phys_low;
228826947304SEvan Yan 
228926947304SEvan Yan 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
229026947304SEvan Yan 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
229126947304SEvan Yan 				else
229226947304SEvan Yan 					mem_type = NDI_RA_TYPE_MEM;
229326947304SEvan Yan 				/* allocate memory space from the allocator */
229426947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
229526947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
229626947304SEvan Yan 				    != NDI_SUCCESS) {
229726947304SEvan Yan 					DEBUG0("Failed to allocate 32b mem\n");
229826947304SEvan Yan 					kmem_free(assigned, length);
229926947304SEvan Yan 					return (PCICFG_NORESRC);
230026947304SEvan Yan 				}
230126947304SEvan Yan 
230226947304SEvan Yan 				break;
230326947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
230426947304SEvan Yan 				request.ra_addr = (uint64_t)
230526947304SEvan Yan 				    assigned[i].pci_phys_low;
230626947304SEvan Yan 
230726947304SEvan Yan 				/* allocate I/O space from the allocator */
230826947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
230926947304SEvan Yan 				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
231026947304SEvan Yan 				    != NDI_SUCCESS) {
231126947304SEvan Yan 					DEBUG0("Failed to allocate I/O\n");
231226947304SEvan Yan 					kmem_free(assigned, length);
231326947304SEvan Yan 					return (PCICFG_NORESRC);
231426947304SEvan Yan 				}
231526947304SEvan Yan 
231626947304SEvan Yan 				break;
231726947304SEvan Yan 			default:
231826947304SEvan Yan 				DEBUG0("Unknown register type\n");
231926947304SEvan Yan 				kmem_free(assigned, length);
232026947304SEvan Yan 				return (PCICFG_FAILURE);
232126947304SEvan Yan 			} /* switch */
232226947304SEvan Yan 		}
232326947304SEvan Yan 	}
232426947304SEvan Yan 
232526947304SEvan Yan 	(void) pcicfg_device_on(handle);
232626947304SEvan Yan 	kmem_free(assigned, length);
232726947304SEvan Yan 
232826947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
232926947304SEvan Yan 
233026947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
233126947304SEvan Yan 	return (PCICFG_SUCCESS);
233226947304SEvan Yan }
233326947304SEvan Yan 
233423c35297Sanish #ifdef	DEBUG
233523c35297Sanish /*
233623c35297Sanish  * This function is useful in debug mode, where we can measure how
233723c35297Sanish  * much memory was wasted/unallocated in bridge device's domain.
233823c35297Sanish  */
233923c35297Sanish static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)234023c35297Sanish pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
234123c35297Sanish {
234223c35297Sanish 	uint64_t len = 0;
234323c35297Sanish 	uint32_t count = 0;
234423c35297Sanish 
234523c35297Sanish 	do {
234623c35297Sanish 		len += hole->len;
234723c35297Sanish 		hole = hole->next;
234823c35297Sanish 		count++;
234923c35297Sanish 	} while (hole);
235023c35297Sanish 	*hole_count = count;
235123c35297Sanish 	return (len);
235223c35297Sanish }
235323c35297Sanish #endif
235423c35297Sanish 
235523c35297Sanish /*
235623c35297Sanish  * This function frees data structures that hold the hole information
235723c35297Sanish  * which are allocated in pcicfg_alloc_hole(). This is not freeing
235823c35297Sanish  * any memory allocated through NDI calls.
235923c35297Sanish  */
236023c35297Sanish static void
pcicfg_free_hole(hole_t * addr_hole)236123c35297Sanish pcicfg_free_hole(hole_t *addr_hole)
236223c35297Sanish {
236323c35297Sanish 	hole_t *nhole, *hole = addr_hole->next;
236423c35297Sanish 
236523c35297Sanish 	while (hole) {
236623c35297Sanish 		nhole = hole->next;
236723c35297Sanish 		kmem_free(hole, sizeof (hole_t));
236823c35297Sanish 		hole = nhole;
236923c35297Sanish 	}
237023c35297Sanish }
237123c35297Sanish 
237223c35297Sanish static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)237323c35297Sanish pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
237423c35297Sanish {
237523c35297Sanish 	uint64_t actual_hole_start, ostart, olen;
237623c35297Sanish 	hole_t	*hole = addr_hole, *thole, *nhole;
237723c35297Sanish 
237823c35297Sanish 	do {
237923c35297Sanish 		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
238023c35297Sanish 		if (((actual_hole_start - hole->start) + length) <= hole->len) {
238123c35297Sanish 			DEBUG3("hole found. start %llx, len %llx, req=0x%x\n",
238223c35297Sanish 			    hole->start, hole->len, length);
238323c35297Sanish 			ostart = hole->start;
238423c35297Sanish 			olen = hole->len;
238523c35297Sanish 			/* current hole parameters adjust */
238623c35297Sanish 			if ((actual_hole_start - hole->start) == 0) {
238723c35297Sanish 				hole->start += length;
238823c35297Sanish 				hole->len -= length;
238923c35297Sanish 				if (hole->start > *alast)
239023c35297Sanish 					*alast = hole->start;
239123c35297Sanish 			} else {
239223c35297Sanish 				hole->len = actual_hole_start - hole->start;
239323c35297Sanish 				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
239423c35297Sanish 				    KM_SLEEP);
239523c35297Sanish 				nhole->start = actual_hole_start + length;
239623c35297Sanish 				nhole->len = (ostart + olen) - nhole->start;
239723c35297Sanish 				nhole->next = NULL;
239823c35297Sanish 				thole = hole->next;
239923c35297Sanish 				hole->next = nhole;
240023c35297Sanish 				nhole->next = thole;
240123c35297Sanish 				if (nhole->start > *alast)
240223c35297Sanish 					*alast = nhole->start;
240323c35297Sanish 				DEBUG2("put new hole to %llx, %llx\n",
240423c35297Sanish 				    nhole->start, nhole->len);
240523c35297Sanish 			}
240623c35297Sanish 			DEBUG2("adjust current hole to %llx, %llx\n",
240723c35297Sanish 			    hole->start, hole->len);
240823c35297Sanish 			break;
240923c35297Sanish 		}
241023c35297Sanish 		actual_hole_start = 0;
241123c35297Sanish 		hole = hole->next;
241223c35297Sanish 	} while (hole);
241323c35297Sanish 
241423c35297Sanish 	DEBUG1("return hole at %llx\n", actual_hole_start);
241523c35297Sanish 	return (actual_hole_start);
241623c35297Sanish }
241723c35297Sanish 
241823c35297Sanish static void
pcicfg_get_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)241926947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
242023c35297Sanish {
242123c35297Sanish 	uint64_t new_mem;
242223c35297Sanish 
242323c35297Sanish 	/* See if there is a hole, that can hold this request. */
242423c35297Sanish 	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
242523c35297Sanish 	    length);
242623c35297Sanish 	if (new_mem) {	/* if non-zero, found a hole. */
242723c35297Sanish 		if (ans != NULL)
242823c35297Sanish 			*ans = new_mem;
242923c35297Sanish 	} else
243023c35297Sanish 		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
243123c35297Sanish 		    length, ddi_get_name(entry->dip));
243223c35297Sanish }
243323c35297Sanish 
243423c35297Sanish static void
pcicfg_get_io(pcicfg_phdl_t * entry,uint32_t length,uint32_t * ans)2435ffb64830SJordan Paige Hendricks pcicfg_get_io(pcicfg_phdl_t *entry, uint32_t length, uint32_t *ans)
243623c35297Sanish {
243723c35297Sanish 	uint32_t new_io;
243823c35297Sanish 	uint64_t io_last;
243923c35297Sanish 
244023c35297Sanish 	/*
244123c35297Sanish 	 * See if there is a hole, that can hold this request.
244223c35297Sanish 	 * Pass 64 bit parameters and then truncate to 32 bit.
244323c35297Sanish 	 */
244423c35297Sanish 	io_last = entry->io_last;
244523c35297Sanish 	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
244623c35297Sanish 	if (new_io) {	/* if non-zero, found a hole. */
244723c35297Sanish 		entry->io_last = (uint32_t)io_last;
244823c35297Sanish 		if (ans != NULL)
244923c35297Sanish 			*ans = new_io;
245023c35297Sanish 	} else
245123c35297Sanish 		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
245223c35297Sanish 		    length, ddi_get_name(entry->dip));
245323c35297Sanish }
245423c35297Sanish 
245523c35297Sanish static void
pcicfg_get_pf_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)245626947304SEvan Yan pcicfg_get_pf_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
245723c35297Sanish {
245823c35297Sanish 	uint64_t new_mem;
245923c35297Sanish 
246023c35297Sanish 	/* See if there is a hole, that can hold this request. */
246123c35297Sanish 	new_mem = pcicfg_alloc_hole(&entry->pf_mem_hole, &entry->pf_memory_last,
246223c35297Sanish 	    length);
246323c35297Sanish 	if (new_mem) {	/* if non-zero, found a hole. */
246423c35297Sanish 		if (ans != NULL)
246523c35297Sanish 			*ans = new_mem;
246623c35297Sanish 	} else
246723c35297Sanish 		cmn_err(CE_WARN, "No %u bytes PF memory window for %s\n",
246823c35297Sanish 		    length, ddi_get_name(entry->dip));
246923c35297Sanish }
247023c35297Sanish 
2471ae5a8bedSAndy Fiddaman #ifdef __sparc
247223c35297Sanish static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)247323c35297Sanish pcicfg_sum_resources(dev_info_t *dip, void *hdl)
247423c35297Sanish {
247523c35297Sanish 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
247623c35297Sanish 	pci_regspec_t *pci_rp;
247723c35297Sanish 	int length;
247823c35297Sanish 	int rcount;
247923c35297Sanish 	int i;
248023c35297Sanish 	ndi_ra_request_t *pf_mem_request;
248123c35297Sanish 	ndi_ra_request_t *mem_request;
248223c35297Sanish 	ndi_ra_request_t *io_request;
248323c35297Sanish 	uint8_t header_type;
248423c35297Sanish 	ddi_acc_handle_t handle;
248523c35297Sanish 
248623c35297Sanish 	entry->error = PCICFG_SUCCESS;
248723c35297Sanish 
248823c35297Sanish 	pf_mem_request = &entry->pf_mem_req;
248923c35297Sanish 	mem_request = &entry->mem_req;
249023c35297Sanish 	io_request =  &entry->io_req;
249123c35297Sanish 
249223c35297Sanish 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
249323c35297Sanish 		DEBUG0("Failed to map config space!\n");
249423c35297Sanish 		entry->error = PCICFG_FAILURE;
249523c35297Sanish 		return (DDI_WALK_TERMINATE);
249623c35297Sanish 	}
249723c35297Sanish 
249823c35297Sanish 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
249923c35297Sanish 
250023c35297Sanish 	/*
250123c35297Sanish 	 * If its a bridge - just record the highest bus seen
250223c35297Sanish 	 */
250323c35297Sanish 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
250423c35297Sanish 
250523c35297Sanish 		if (entry->highest_bus < pci_config_get8(handle,
250623c35297Sanish 		    PCI_BCNF_SECBUS)) {
250723c35297Sanish 			entry->highest_bus =
250823c35297Sanish 			    pci_config_get8(handle, PCI_BCNF_SECBUS);
250923c35297Sanish 		}
251023c35297Sanish 		(void) pcicfg_config_teardown(&handle);
251123c35297Sanish 		entry->error = PCICFG_FAILURE;
251223c35297Sanish 		return (DDI_WALK_CONTINUE);
251323c35297Sanish 	} else {
251426947304SEvan Yan 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
251526947304SEvan Yan 		    "reg", (caddr_t)&pci_rp, &length) != DDI_PROP_SUCCESS) {
251623c35297Sanish 			/*
251723c35297Sanish 			 * If one node in (the subtree of nodes)
251823c35297Sanish 			 * doesn't have a "reg" property fail the
251923c35297Sanish 			 * allocation.
252023c35297Sanish 			 */
252123c35297Sanish 			entry->memory_len = 0;
252223c35297Sanish 			entry->io_len = 0;
252323c35297Sanish 			entry->pf_memory_len = 0;
252423c35297Sanish 			entry->error = PCICFG_FAILURE;
25251fb5b786Sprasad 			(void) pcicfg_config_teardown(&handle);
252623c35297Sanish 			return (DDI_WALK_TERMINATE);
252723c35297Sanish 		}
252823c35297Sanish 		/*
252923c35297Sanish 		 * For each "reg" property with a length, add that to the
253023c35297Sanish 		 * total memory (or I/O) to allocate.
253123c35297Sanish 		 */
253223c35297Sanish 		rcount = length / sizeof (pci_regspec_t);
253323c35297Sanish 
253423c35297Sanish 		for (i = 0; i < rcount; i++) {
253523c35297Sanish 
253623c35297Sanish 			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
253723c35297Sanish 
253823c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
253923c35297Sanish 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
254023c35297Sanish 					pf_mem_request->ra_len =
254123c35297Sanish 					    pci_rp[i].pci_size_low +
254226947304SEvan Yan 					    PCICFG_ROUND_UP(
254326947304SEvan Yan 					    pf_mem_request->ra_len,
254423c35297Sanish 					    pci_rp[i].pci_size_low);
254523c35297Sanish 					DEBUG1("ADDING 32 --->0x%x\n",
254623c35297Sanish 					    pci_rp[i].pci_size_low);
254723c35297Sanish 				} else {
254823c35297Sanish 					mem_request->ra_len =
254923c35297Sanish 					    pci_rp[i].pci_size_low +
255023c35297Sanish 					    PCICFG_ROUND_UP(mem_request->ra_len,
255123c35297Sanish 					    pci_rp[i].pci_size_low);
255223c35297Sanish 					DEBUG1("ADDING 32 --->0x%x\n",
255323c35297Sanish 					    pci_rp[i].pci_size_low);
255423c35297Sanish 				}
255523c35297Sanish 
255623c35297Sanish 				break;
255723c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
255823c35297Sanish 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
255923c35297Sanish 					pf_mem_request->ra_len =
256023c35297Sanish 					    pci_rp[i].pci_size_low +
256126947304SEvan Yan 					    PCICFG_ROUND_UP(
256226947304SEvan Yan 					    pf_mem_request->ra_len,
256323c35297Sanish 					    pci_rp[i].pci_size_low);
256423c35297Sanish 					DEBUG1("ADDING 64 --->0x%x\n",
256523c35297Sanish 					    pci_rp[i].pci_size_low);
256623c35297Sanish 				} else {
256723c35297Sanish 					mem_request->ra_len =
256823c35297Sanish 					    pci_rp[i].pci_size_low +
256923c35297Sanish 					    PCICFG_ROUND_UP(mem_request->ra_len,
257023c35297Sanish 					    pci_rp[i].pci_size_low);
257123c35297Sanish 					DEBUG1("ADDING 64 --->0x%x\n",
257223c35297Sanish 					    pci_rp[i].pci_size_low);
257323c35297Sanish 				}
257423c35297Sanish 
257523c35297Sanish 				break;
257623c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
257723c35297Sanish 				io_request->ra_len =
257823c35297Sanish 				    pci_rp[i].pci_size_low +
257923c35297Sanish 				    PCICFG_ROUND_UP(io_request->ra_len,
258023c35297Sanish 				    pci_rp[i].pci_size_low);
258123c35297Sanish 				DEBUG1("ADDING I/O --->0x%x\n",
258223c35297Sanish 				    pci_rp[i].pci_size_low);
258323c35297Sanish 				break;
258423c35297Sanish 			default:
258523c35297Sanish 				/* Config space register - not included */
258623c35297Sanish 				break;
258723c35297Sanish 			}
258823c35297Sanish 		}
258923c35297Sanish 
259023c35297Sanish 		/*
259123c35297Sanish 		 * free the memory allocated by ddi_getlongprop
259223c35297Sanish 		 */
259323c35297Sanish 		kmem_free(pci_rp, length);
259423c35297Sanish 
259523c35297Sanish 		/*
259623c35297Sanish 		 * continue the walk to the next sibling to sum memory
259723c35297Sanish 		 */
259823c35297Sanish 
259923c35297Sanish 		(void) pcicfg_config_teardown(&handle);
260023c35297Sanish 
260123c35297Sanish 		return (DDI_WALK_CONTINUE);
260223c35297Sanish 	}
260323c35297Sanish }
2604ae5a8bedSAndy Fiddaman #endif /* __sparc */
260523c35297Sanish 
260623c35297Sanish static int
pcicfg_free_bridge_resources(dev_info_t * dip)260723c35297Sanish pcicfg_free_bridge_resources(dev_info_t *dip)
260823c35297Sanish {
260923c35297Sanish 	ppb_ranges_t		*ranges;
261023c35297Sanish 	uint_t			*bus;
261123c35297Sanish 	int			k;
26121fb5b786Sprasad 	int			length = 0;
261323c35297Sanish 	int			i;
261423c35297Sanish 
261523c35297Sanish 
261626947304SEvan Yan 	if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
261726947304SEvan Yan 	    "ranges", (caddr_t)&ranges, &length)) != DDI_PROP_SUCCESS) {
261823c35297Sanish 		DEBUG0("Failed to read ranges property\n");
261923c35297Sanish 		if (ddi_get_child(dip)) {
262023c35297Sanish 			cmn_err(CE_WARN, "No ranges property found for %s",
262123c35297Sanish 			    ddi_get_name(dip));
262223c35297Sanish 			/*
262323c35297Sanish 			 * strictly speaking, we can check for children with
262423c35297Sanish 			 * assigned-addresses but for now it is better to
262523c35297Sanish 			 * be conservative and assume that if there are child
262623c35297Sanish 			 * nodes, then they do consume PCI memory or IO
262723c35297Sanish 			 * resources, Hence return failure.
262823c35297Sanish 			 */
262923c35297Sanish 			return (PCICFG_FAILURE);
263023c35297Sanish 		}
263123c35297Sanish 		length = 0;
263223c35297Sanish 	}
263323c35297Sanish 
263423c35297Sanish 	for (i = 0; i < length / sizeof (ppb_ranges_t); i++) {
263523c35297Sanish 		char *mem_type;
263623c35297Sanish 
263726947304SEvan Yan 		if (ranges[i].size_low != 0 || ranges[i].size_high != 0) {
263823c35297Sanish 			switch (ranges[i].parent_high & PCI_REG_ADDR_M) {
263923c35297Sanish 			case PCI_ADDR_IO:
264026947304SEvan Yan 				DEBUG2("Free I/O    base/length = "
264126947304SEvan Yan 				    "[0x%x]/[0x%x]\n", ranges[i].child_low,
264223c35297Sanish 				    ranges[i].size_low);
264323c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
264423c35297Sanish 				    (uint64_t)ranges[i].child_low,
264523c35297Sanish 				    (uint64_t)ranges[i].size_low,
264623c35297Sanish 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
264723c35297Sanish 				    != NDI_SUCCESS) {
264823c35297Sanish 					DEBUG0("Trouble freeing "
264923c35297Sanish 					    "PCI i/o space\n");
265023c35297Sanish 					kmem_free(ranges, length);
265123c35297Sanish 					return (PCICFG_FAILURE);
265223c35297Sanish 				}
265323c35297Sanish 				break;
265423c35297Sanish 			case PCI_ADDR_MEM32:
265523c35297Sanish 			case PCI_ADDR_MEM64:
265623c35297Sanish 				if (ranges[i].parent_high & PCI_REG_PF_M) {
265726947304SEvan Yan 					DEBUG3("Free PF Memory base/length = "
265826947304SEvan Yan 					    "[0x%x.0x%x]/[0x%x]\n",
265923c35297Sanish 					    ranges[i].child_mid,
266023c35297Sanish 					    ranges[i].child_low,
266126947304SEvan Yan 					    ranges[i].size_low);
266223c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
266323c35297Sanish 				} else {
266423c35297Sanish 					DEBUG3("Free Memory base/length"
266523c35297Sanish 					    " = [0x%x.0x%x]/[0x%x]\n",
266623c35297Sanish 					    ranges[i].child_mid,
266723c35297Sanish 					    ranges[i].child_low,
266823c35297Sanish 					    ranges[i].size_low)
266923c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
267023c35297Sanish 				}
267123c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
267226947304SEvan Yan 				    PCICFG_LADDR(ranges[i].child_low,
267323c35297Sanish 				    ranges[i].child_mid),
267423c35297Sanish 				    (uint64_t)ranges[i].size_low,
267526947304SEvan Yan 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
267623c35297Sanish 					DEBUG0("Trouble freeing "
267723c35297Sanish 					    "PCI memory space\n");
267823c35297Sanish 					kmem_free(ranges, length);
267923c35297Sanish 					return (PCICFG_FAILURE);
268023c35297Sanish 				}
268123c35297Sanish 				break;
268223c35297Sanish 			default:
268323c35297Sanish 				DEBUG0("Unknown memory space\n");
268423c35297Sanish 				break;
268523c35297Sanish 			}
268623c35297Sanish 		}
268723c35297Sanish 	}
268823c35297Sanish 
268923c35297Sanish 	if (length)
269023c35297Sanish 		kmem_free(ranges, length);
269123c35297Sanish 
269226947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
269326947304SEvan Yan 	    "bus-range", (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
269423c35297Sanish 		DEBUG0("Failed to read bus-range property\n");
269523c35297Sanish 		return (PCICFG_FAILURE);
269623c35297Sanish 	}
269723c35297Sanish 
269823c35297Sanish 	DEBUG2("Need to free bus [%d] range [%d]\n",
269923c35297Sanish 	    bus[0], bus[1] - bus[0] + 1);
270023c35297Sanish 
270126947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
270226947304SEvan Yan 	    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
270326947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
270423c35297Sanish 		DEBUG0("Failed to free a bus number\n");
27051fb5b786Sprasad 		kmem_free(bus, k);
270623c35297Sanish 		return (PCICFG_FAILURE);
270723c35297Sanish 	}
27081fb5b786Sprasad 
27091fb5b786Sprasad 	kmem_free(bus, k);
271023c35297Sanish 	return (PCICFG_SUCCESS);
271123c35297Sanish }
271223c35297Sanish 
271323c35297Sanish static int
pcicfg_free_device_resources(dev_info_t * dip)271423c35297Sanish pcicfg_free_device_resources(dev_info_t *dip)
271523c35297Sanish {
271623c35297Sanish 	pci_regspec_t *assigned;
271723c35297Sanish 
271823c35297Sanish 	int length;
271923c35297Sanish 	int acount;
272023c35297Sanish 	int i;
272123c35297Sanish 
272226947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
272326947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &length)
272426947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
272523c35297Sanish 		DEBUG0("Failed to read assigned-addresses property\n");
272623c35297Sanish 		return (PCICFG_FAILURE);
272723c35297Sanish 	}
272823c35297Sanish 
272923c35297Sanish 	/*
273023c35297Sanish 	 * For each "assigned-addresses" property entry with a length,
273123c35297Sanish 	 * call the memory allocation routines to return the
273223c35297Sanish 	 * resource.
273323c35297Sanish 	 */
273423c35297Sanish 	acount = length / sizeof (pci_regspec_t);
273523c35297Sanish 	for (i = 0; i < acount; i++) {
273623c35297Sanish 		char *mem_type;
273723c35297Sanish 
273823c35297Sanish 		/*
273923c35297Sanish 		 * Free the resource if the size of it is not zero.
274023c35297Sanish 		 */
274123c35297Sanish 		if ((assigned[i].pci_size_low != 0)||
274223c35297Sanish 		    (assigned[i].pci_size_hi != 0)) {
274323c35297Sanish 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
274423c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
274523c35297Sanish 				/*
274623c35297Sanish 				 * Check the assigned address for zero.
274723c35297Sanish 				 * (Workaround for Devconf (x86) bug to
274823c35297Sanish 				 * skip bogus entry for ROM base address
274923c35297Sanish 				 * register. If the assigned address is
275023c35297Sanish 				 * zero then ignore the entry
275123c35297Sanish 				 * (see bugid 4281306)).
275223c35297Sanish 				 */
275323c35297Sanish 				if (assigned[i].pci_phys_low == 0)
275423c35297Sanish 					break; /* ignore the entry */
275523c35297Sanish 
275623c35297Sanish 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
275723c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
275823c35297Sanish 				else
275923c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
276023c35297Sanish 
276123c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
276223c35297Sanish 				    (uint64_t)assigned[i].pci_phys_low,
276323c35297Sanish 				    (uint64_t)assigned[i].pci_size_low,
276423c35297Sanish 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
276523c35297Sanish 					DEBUG0("Trouble freeing "
276623c35297Sanish 					    "PCI memory space\n");
27671fb5b786Sprasad 					kmem_free(assigned, length);
276823c35297Sanish 					return (PCICFG_FAILURE);
276923c35297Sanish 				}
277023c35297Sanish 
277123c35297Sanish 				DEBUG4("Returned 0x%x of 32 bit %s space"
277223c35297Sanish 				    " @ 0x%x from register 0x%x\n",
277326947304SEvan Yan 				    assigned[i].pci_size_low, mem_type,
277423c35297Sanish 				    assigned[i].pci_phys_low,
277523c35297Sanish 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
277623c35297Sanish 
277723c35297Sanish 			break;
277823c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
277923c35297Sanish 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
278023c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
278123c35297Sanish 				else
278223c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
278323c35297Sanish 
278423c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
278523c35297Sanish 				    PCICFG_LADDR(assigned[i].pci_phys_low,
278623c35297Sanish 				    assigned[i].pci_phys_mid),
278723c35297Sanish 				    (uint64_t)assigned[i].pci_size_low,
278823c35297Sanish 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
278923c35297Sanish 					DEBUG0("Trouble freeing "
279023c35297Sanish 					    "PCI memory space\n");
27911fb5b786Sprasad 					kmem_free(assigned, length);
279223c35297Sanish 					return (PCICFG_FAILURE);
279323c35297Sanish 				}
279423c35297Sanish 
279523c35297Sanish 				DEBUG5("Returned 0x%x of 64 bit %s space"
279623c35297Sanish 				    " @ 0x%x.0x%x from register 0x%x\n",
279723c35297Sanish 				    assigned[i].pci_size_low,
279826947304SEvan Yan 				    mem_type, assigned[i].pci_phys_mid,
279923c35297Sanish 				    assigned[i].pci_phys_low,
280023c35297Sanish 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
280123c35297Sanish 
280223c35297Sanish 			break;
280323c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
280423c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
280523c35297Sanish 				    (uint64_t)assigned[i].pci_phys_low,
280623c35297Sanish 				    (uint64_t)assigned[i].pci_size_low,
28071fb5b786Sprasad 				    NDI_RA_TYPE_IO, NDI_RA_PASS) !=
28081fb5b786Sprasad 				    NDI_SUCCESS) {
280923c35297Sanish 					DEBUG0("Trouble freeing "
281023c35297Sanish 					    "PCI IO space\n");
28111fb5b786Sprasad 					kmem_free(assigned, length);
281223c35297Sanish 					return (PCICFG_FAILURE);
281323c35297Sanish 				}
281426947304SEvan Yan 				DEBUG3("Returned 0x%x of IO space @ 0x%x from "
281526947304SEvan Yan 				    "register 0x%x\n", assigned[i].pci_size_low,
281623c35297Sanish 				    assigned[i].pci_phys_low,
281723c35297Sanish 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
281823c35297Sanish 			break;
281923c35297Sanish 			default:
282023c35297Sanish 				DEBUG0("Unknown register type\n");
282123c35297Sanish 				kmem_free(assigned, length);
282223c35297Sanish 				return (PCICFG_FAILURE);
282323c35297Sanish 			} /* switch */
282423c35297Sanish 		}
282523c35297Sanish 	}
282623c35297Sanish 	kmem_free(assigned, length);
282723c35297Sanish 	return (PCICFG_SUCCESS);
282823c35297Sanish }
282923c35297Sanish 
283023c35297Sanish static int
pcicfg_free_resources(dev_info_t * dip,pcicfg_flags_t flags)283126947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
283223c35297Sanish {
283323c35297Sanish 	ddi_acc_handle_t handle;
283423c35297Sanish 	uint8_t header_type;
283523c35297Sanish 
283623c35297Sanish 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
283723c35297Sanish 		DEBUG0("Failed to map config space!\n");
283823c35297Sanish 		return (PCICFG_FAILURE);
283923c35297Sanish 	}
284023c35297Sanish 
284123c35297Sanish 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
284223c35297Sanish 
284323c35297Sanish 	(void) pci_config_teardown(&handle);
284423c35297Sanish 
284523c35297Sanish 	/*
284623c35297Sanish 	 * A different algorithm is used for bridges and leaf devices.
284723c35297Sanish 	 */
284823c35297Sanish 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
284926947304SEvan Yan 		/*
285026947304SEvan Yan 		 * We only support readonly probing for leaf devices.
285126947304SEvan Yan 		 */
285226947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
285326947304SEvan Yan 			return (PCICFG_FAILURE);
285426947304SEvan Yan 
285523c35297Sanish 		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
285623c35297Sanish 			DEBUG0("Failed freeing up bridge resources\n");
285723c35297Sanish 			return (PCICFG_FAILURE);
285823c35297Sanish 		}
285923c35297Sanish 	} else {
286023c35297Sanish 		if (pcicfg_free_device_resources(dip) != PCICFG_SUCCESS) {
286123c35297Sanish 			DEBUG0("Failed freeing up device resources\n");
286223c35297Sanish 			return (PCICFG_FAILURE);
286323c35297Sanish 		}
286423c35297Sanish 	}
286523c35297Sanish 
286623c35297Sanish 	return (PCICFG_SUCCESS);
286723c35297Sanish }
286823c35297Sanish 
286923c35297Sanish #ifndef _DONT_USE_1275_GENERIC_NAMES
287023c35297Sanish static char *
pcicfg_get_class_name(uint32_t classcode)287123c35297Sanish pcicfg_get_class_name(uint32_t classcode)
287223c35297Sanish {
287323c35297Sanish 	struct pcicfg_name_entry *ptr;
287423c35297Sanish 
287523c35297Sanish 	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
287623c35297Sanish 		if (ptr->class_code == classcode) {
287723c35297Sanish 			return (ptr->name);
287823c35297Sanish 		}
287923c35297Sanish 	}
288023c35297Sanish 	return (NULL);
288123c35297Sanish }
288223c35297Sanish #endif /* _DONT_USE_1275_GENERIC_NAMES */
288323c35297Sanish 
288423c35297Sanish static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)288523c35297Sanish pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
288623c35297Sanish {
288723c35297Sanish 	struct pcicfg_find_ctrl ctrl;
288823c35297Sanish 
288923c35297Sanish 	ctrl.device = device;
289023c35297Sanish 	ctrl.function = function;
289123c35297Sanish 	ctrl.dip = NULL;
289223c35297Sanish 
28933fe80ca4SDan Cross 	ndi_devi_enter(dip);
289423c35297Sanish 	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
28953fe80ca4SDan Cross 	ndi_devi_exit(dip);
289623c35297Sanish 
289723c35297Sanish 	return (ctrl.dip);
289823c35297Sanish }
289923c35297Sanish 
290023c35297Sanish static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)290123c35297Sanish pcicfg_match_dev(dev_info_t *dip, void *hdl)
290223c35297Sanish {
290323c35297Sanish 	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
290423c35297Sanish 	pci_regspec_t *pci_rp;
290523c35297Sanish 	int length;
290623c35297Sanish 	int pci_dev;
290723c35297Sanish 	int pci_func;
290823c35297Sanish 
290926947304SEvan Yan 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
291026947304SEvan Yan 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
291123c35297Sanish 		ctrl->dip = NULL;
291223c35297Sanish 		return (DDI_WALK_TERMINATE);
291323c35297Sanish 	}
291423c35297Sanish 
291523c35297Sanish 	/* get the PCI device address info */
291623c35297Sanish 	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
291723c35297Sanish 	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
291823c35297Sanish 
291923c35297Sanish 	/*
292023c35297Sanish 	 * free the memory allocated by ddi_prop_lookup_int_array
292123c35297Sanish 	 */
292223c35297Sanish 	ddi_prop_free(pci_rp);
292323c35297Sanish 
292423c35297Sanish 
292523c35297Sanish 	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
292623c35297Sanish 		/* found the match for the specified device address */
292723c35297Sanish 		ctrl->dip = dip;
292823c35297Sanish 		return (DDI_WALK_TERMINATE);
292923c35297Sanish 	}
293023c35297Sanish 
293123c35297Sanish 	/*
293223c35297Sanish 	 * continue the walk to the next sibling to look for a match.
293323c35297Sanish 	 */
293423c35297Sanish 	return (DDI_WALK_PRUNECHILD);
293523c35297Sanish }
293623c35297Sanish 
293723c35297Sanish static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)293823c35297Sanish pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
293923c35297Sanish {
294023c35297Sanish 	int		alen;
294123c35297Sanish 	pci_regspec_t	*assigned;
294223c35297Sanish 	caddr_t		newreg;
294323c35297Sanish 	uint_t		status;
294423c35297Sanish 
294523c35297Sanish 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
294623c35297Sanish 	    "assigned-addresses", (caddr_t)&assigned, &alen);
294723c35297Sanish 	switch (status) {
294823c35297Sanish 		case DDI_PROP_SUCCESS:
294923c35297Sanish 		break;
295023c35297Sanish 		case DDI_PROP_NO_MEMORY:
295123c35297Sanish 			DEBUG0("no memory for assigned-addresses property\n");
295223c35297Sanish 			return (PCICFG_FAILURE);
295323c35297Sanish 		default:
295423c35297Sanish 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
295523c35297Sanish 			    "assigned-addresses", (int *)newone,
295623c35297Sanish 			    sizeof (*newone)/sizeof (int));
295723c35297Sanish 			return (PCICFG_SUCCESS);
295823c35297Sanish 	}
295923c35297Sanish 
296023c35297Sanish 	/*
296123c35297Sanish 	 * Allocate memory for the existing
296223c35297Sanish 	 * assigned-addresses(s) plus one and then
296323c35297Sanish 	 * build it.
296423c35297Sanish 	 */
296523c35297Sanish 
296623c35297Sanish 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
296723c35297Sanish 
296823c35297Sanish 	bcopy(assigned, newreg, alen);
296923c35297Sanish 	bcopy(newone, newreg + alen, sizeof (*newone));
297023c35297Sanish 
297123c35297Sanish 	/*
297223c35297Sanish 	 * Write out the new "assigned-addresses" spec
297323c35297Sanish 	 */
297423c35297Sanish 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
297523c35297Sanish 	    "assigned-addresses", (int *)newreg,
297623c35297Sanish 	    (alen + sizeof (*newone))/sizeof (int));
297723c35297Sanish 
297823c35297Sanish 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
297923c35297Sanish 	kmem_free(assigned, alen);
298023c35297Sanish 
298123c35297Sanish 	return (PCICFG_SUCCESS);
298223c35297Sanish }
298323c35297Sanish 
298423c35297Sanish static int
pcicfg_update_ranges_prop(dev_info_t * dip,ppb_ranges_t * addition)298523c35297Sanish pcicfg_update_ranges_prop(dev_info_t *dip, ppb_ranges_t *addition)
298623c35297Sanish {
298723c35297Sanish 	int		rlen;
298823c35297Sanish 	ppb_ranges_t	*ranges;
298923c35297Sanish 	caddr_t		newreg;
299023c35297Sanish 	uint_t		status;
299123c35297Sanish 
299226947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
299326947304SEvan Yan 	    "ranges", (caddr_t)&ranges, &rlen);
299423c35297Sanish 
299523c35297Sanish 
299623c35297Sanish 	switch (status) {
299723c35297Sanish 		case DDI_PROP_SUCCESS:
299823c35297Sanish 			break;
299923c35297Sanish 		case DDI_PROP_NO_MEMORY:
300023c35297Sanish 			DEBUG0("ranges present, but unable to get memory\n");
300123c35297Sanish 			return (PCICFG_FAILURE);
300223c35297Sanish 		default:
300323c35297Sanish 			DEBUG0("no ranges property - creating one\n");
300423c35297Sanish 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
300523c35297Sanish 			    dip, "ranges", (int *)addition,
300623c35297Sanish 			    sizeof (ppb_ranges_t)/sizeof (int))
300723c35297Sanish 			    != DDI_SUCCESS) {
300823c35297Sanish 				DEBUG0("Did'nt create ranges property\n");
300923c35297Sanish 				return (PCICFG_FAILURE);
301023c35297Sanish 			}
301123c35297Sanish 			return (PCICFG_SUCCESS);
301223c35297Sanish 	}
301323c35297Sanish 
301423c35297Sanish 	/*
301523c35297Sanish 	 * Allocate memory for the existing ranges plus one and then
301623c35297Sanish 	 * build it.
301723c35297Sanish 	 */
301823c35297Sanish 	newreg = kmem_zalloc(rlen+sizeof (ppb_ranges_t), KM_SLEEP);
301923c35297Sanish 
302023c35297Sanish 	bcopy(ranges, newreg, rlen);
302123c35297Sanish 	bcopy(addition, newreg + rlen, sizeof (ppb_ranges_t));
302223c35297Sanish 
302323c35297Sanish 	/*
302423c35297Sanish 	 * Write out the new "ranges" property
302523c35297Sanish 	 */
302626947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
302726947304SEvan Yan 	    (int *)newreg, (rlen + sizeof (ppb_ranges_t))/sizeof (int));
302823c35297Sanish 
302923c35297Sanish 	DEBUG1("Updating ranges property for %d entries",
303023c35297Sanish 	    rlen / sizeof (ppb_ranges_t) + 1);
303123c35297Sanish 
303223c35297Sanish 	kmem_free((caddr_t)newreg, rlen+sizeof (ppb_ranges_t));
303323c35297Sanish 
303423c35297Sanish 	kmem_free((caddr_t)ranges, rlen);
303523c35297Sanish 
303623c35297Sanish 	return (PCICFG_SUCCESS);
303723c35297Sanish }
303823c35297Sanish 
303923c35297Sanish static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)304023c35297Sanish pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
304123c35297Sanish {
304223c35297Sanish 	int		rlen;
304323c35297Sanish 	pci_regspec_t	*reg;
304423c35297Sanish 	caddr_t		newreg;
304523c35297Sanish 	uint32_t	hiword;
304623c35297Sanish 	pci_regspec_t	addition;
304723c35297Sanish 	uint32_t	size;
304823c35297Sanish 	uint_t		status;
304923c35297Sanish 
305023c35297Sanish 	status = ddi_getlongprop(DDI_DEV_T_ANY,
305123c35297Sanish 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
305223c35297Sanish 
305323c35297Sanish 	switch (status) {
305423c35297Sanish 		case DDI_PROP_SUCCESS:
305523c35297Sanish 		break;
305623c35297Sanish 		case DDI_PROP_NO_MEMORY:
305723c35297Sanish 			DEBUG0("reg present, but unable to get memory\n");
305823c35297Sanish 			return (PCICFG_FAILURE);
305923c35297Sanish 		default:
306023c35297Sanish 			DEBUG0("no reg property\n");
306123c35297Sanish 			return (PCICFG_FAILURE);
306223c35297Sanish 	}
306323c35297Sanish 
306423c35297Sanish 	/*
306523c35297Sanish 	 * Allocate memory for the existing reg(s) plus one and then
306623c35297Sanish 	 * build it.
306723c35297Sanish 	 */
306823c35297Sanish 	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
306923c35297Sanish 
307023c35297Sanish 	/*
307123c35297Sanish 	 * Build the regspec, then add it to the existing one(s)
307223c35297Sanish 	 */
307323c35297Sanish 
307423c35297Sanish 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
307523c35297Sanish 	    PCI_REG_DEV_G(reg->pci_phys_hi),
307623c35297Sanish 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
307723c35297Sanish 
307823c35297Sanish 	if (reg_offset == PCI_CONF_ROM) {
307923c35297Sanish 		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
308023c35297Sanish 		hiword |= PCI_ADDR_MEM32;
308123c35297Sanish 	} else {
308223c35297Sanish 		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
308323c35297Sanish 
308423c35297Sanish 		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
308523c35297Sanish 			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
308623c35297Sanish 				hiword |= PCI_ADDR_MEM32;
308723c35297Sanish 			} else if ((PCI_BASE_TYPE_M & regvalue)
308823c35297Sanish 			    == PCI_BASE_TYPE_ALL) {
308923c35297Sanish 				hiword |= PCI_ADDR_MEM64;
309023c35297Sanish 			}
309123c35297Sanish 			if (regvalue & PCI_BASE_PREF_M)
309223c35297Sanish 				hiword |= PCI_REG_PF_M;
309323c35297Sanish 		} else {
309423c35297Sanish 			hiword |= PCI_ADDR_IO;
309523c35297Sanish 		}
309623c35297Sanish 	}
309723c35297Sanish 
309823c35297Sanish 	addition.pci_phys_hi = hiword;
309923c35297Sanish 	addition.pci_phys_mid = 0;
310023c35297Sanish 	addition.pci_phys_low = 0;
310123c35297Sanish 	addition.pci_size_hi = 0;
310223c35297Sanish 	addition.pci_size_low = size;
310323c35297Sanish 
310423c35297Sanish 	bcopy(reg, newreg, rlen);
310523c35297Sanish 	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
310623c35297Sanish 
310723c35297Sanish 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
310823c35297Sanish 	/*
310923c35297Sanish 	 * Write out the new "reg" property
311023c35297Sanish 	 */
311126947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
311226947304SEvan Yan 	    (int *)newreg, (rlen + sizeof (pci_regspec_t))/sizeof (int));
311323c35297Sanish 
311423c35297Sanish 	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
311523c35297Sanish 	kmem_free((caddr_t)reg, rlen);
311623c35297Sanish 
311723c35297Sanish 	return (PCICFG_SUCCESS);
311823c35297Sanish }
311923c35297Sanish 
312026947304SEvan Yan static int
pcicfg_update_assigned_prop_value(dev_info_t * dip,uint32_t size,uint32_t base,uint32_t base_hi,uint_t reg_offset)312126947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
312226947304SEvan Yan     uint32_t base, uint32_t base_hi, uint_t reg_offset)
312326947304SEvan Yan {
312426947304SEvan Yan 	int		rlen;
312526947304SEvan Yan 	pci_regspec_t	*reg;
312626947304SEvan Yan 	uint32_t	hiword;
312726947304SEvan Yan 	pci_regspec_t	addition;
312826947304SEvan Yan 	uint_t		status;
312926947304SEvan Yan 
313026947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
313126947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
313226947304SEvan Yan 
313326947304SEvan Yan 	switch (status) {
313426947304SEvan Yan 		case DDI_PROP_SUCCESS:
313526947304SEvan Yan 		break;
313626947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
313726947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
313826947304SEvan Yan 			return (PCICFG_FAILURE);
313926947304SEvan Yan 		default:
314026947304SEvan Yan 			/*
314126947304SEvan Yan 			 * Since the config space "reg" entry should have been
314226947304SEvan Yan 			 * created, we expect a "reg" property already
314326947304SEvan Yan 			 * present here.
314426947304SEvan Yan 			 */
314526947304SEvan Yan 			DEBUG0("no reg property\n");
314626947304SEvan Yan 			return (PCICFG_FAILURE);
314726947304SEvan Yan 	}
314826947304SEvan Yan 
314926947304SEvan Yan 	/*
315026947304SEvan Yan 	 * Build the regspec, then add it to the existing one(s)
315126947304SEvan Yan 	 */
315226947304SEvan Yan 
315326947304SEvan Yan 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
315426947304SEvan Yan 	    PCI_REG_DEV_G(reg->pci_phys_hi),
315526947304SEvan Yan 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
315626947304SEvan Yan 
315726947304SEvan Yan 	hiword |= PCI_REG_REL_M;
315826947304SEvan Yan 
315926947304SEvan Yan 	if (reg_offset == PCI_CONF_ROM) {
316026947304SEvan Yan 		hiword |= PCI_ADDR_MEM32;
316126947304SEvan Yan 
316226947304SEvan Yan 		base = PCI_BASE_ROM_ADDR_M & base;
316326947304SEvan Yan 	} else {
316426947304SEvan Yan 		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
316526947304SEvan Yan 			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
316626947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
316726947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & base)
316826947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
316926947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
317026947304SEvan Yan 			}
317126947304SEvan Yan 			if (base & PCI_BASE_PREF_M)
317226947304SEvan Yan 				hiword |= PCI_REG_PF_M;
317326947304SEvan Yan 
317426947304SEvan Yan 			base = PCI_BASE_M_ADDR_M & base;
317526947304SEvan Yan 		} else {
317626947304SEvan Yan 			hiword |= PCI_ADDR_IO;
317726947304SEvan Yan 
317826947304SEvan Yan 			base = PCI_BASE_IO_ADDR_M & base;
317926947304SEvan Yan 			base_hi = 0;
318026947304SEvan Yan 		}
318126947304SEvan Yan 	}
318226947304SEvan Yan 
318326947304SEvan Yan 	addition.pci_phys_hi = hiword;
318426947304SEvan Yan 	addition.pci_phys_mid = base_hi;
318526947304SEvan Yan 	addition.pci_phys_low = base;
318626947304SEvan Yan 	addition.pci_size_hi = 0;
318726947304SEvan Yan 	addition.pci_size_low = size;
318826947304SEvan Yan 
318926947304SEvan Yan 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
319026947304SEvan Yan 
319126947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
319226947304SEvan Yan 
319326947304SEvan Yan 	return (pcicfg_update_assigned_prop(dip, &addition));
319426947304SEvan Yan }
319526947304SEvan Yan 
319623c35297Sanish static void
pcicfg_device_on(ddi_acc_handle_t config_handle)319723c35297Sanish pcicfg_device_on(ddi_acc_handle_t config_handle)
319823c35297Sanish {
319923c35297Sanish 	/*
320023c35297Sanish 	 * Enable memory, IO, and bus mastership
320123c35297Sanish 	 * XXX should we enable parity, SERR#,
320223c35297Sanish 	 * fast back-to-back, and addr. stepping?
320323c35297Sanish 	 */
320423c35297Sanish 	pci_config_put16(config_handle, PCI_CONF_COMM,
320523c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
320623c35297Sanish }
320723c35297Sanish 
320823c35297Sanish static void
pcicfg_device_off(ddi_acc_handle_t config_handle)320923c35297Sanish pcicfg_device_off(ddi_acc_handle_t config_handle)
321023c35297Sanish {
321123c35297Sanish 	/*
321223c35297Sanish 	 * Disable I/O and memory traffic through the bridge
321323c35297Sanish 	 */
321423c35297Sanish 	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
321523c35297Sanish }
321623c35297Sanish 
321723c35297Sanish static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type)321823c35297Sanish pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type)
321923c35297Sanish {
322023c35297Sanish 	int ret;
322123c35297Sanish 	char device_type[8];
322223c35297Sanish 
322323c35297Sanish 	if (pcie_device_type)
322423c35297Sanish 		(void) strcpy(device_type, "pciex");
322523c35297Sanish 	else
322623c35297Sanish 		(void) strcpy(device_type, "pci");
322723c35297Sanish 
322823c35297Sanish 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
322923c35297Sanish 	    "device_type", device_type)) != DDI_SUCCESS) {
323023c35297Sanish 		return (ret);
323123c35297Sanish 	}
323223c35297Sanish 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
323323c35297Sanish 	    "#address-cells", 3)) != DDI_SUCCESS) {
323423c35297Sanish 		return (ret);
323523c35297Sanish 	}
323626947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 2))
323726947304SEvan Yan 	    != DDI_SUCCESS) {
323823c35297Sanish 		return (ret);
323923c35297Sanish 	}
324023c35297Sanish 	return (PCICFG_SUCCESS);
324123c35297Sanish }
324223c35297Sanish 
324323c35297Sanish /*
324423c35297Sanish  * Program the bus numbers into the bridge
324523c35297Sanish  */
324623c35297Sanish static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,uint_t primary,uint_t secondary,uint_t subordinate)3247ffb64830SJordan Paige Hendricks pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle, uint_t primary,
3248ffb64830SJordan Paige Hendricks     uint_t secondary, uint_t subordinate)
324923c35297Sanish {
325023c35297Sanish 	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
325123c35297Sanish 	    subordinate);
325223c35297Sanish 	/*
325323c35297Sanish 	 * Primary bus#
325423c35297Sanish 	 */
325523c35297Sanish 	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
325623c35297Sanish 
325723c35297Sanish 	/*
325823c35297Sanish 	 * Secondary bus#
325923c35297Sanish 	 */
326023c35297Sanish 	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
326123c35297Sanish 
326223c35297Sanish 	/*
326323c35297Sanish 	 * Set the subordinate bus number to ff in order to pass through any
326423c35297Sanish 	 * type 1 cycle with a bus number higher than the secondary bus#
326523c35297Sanish 	 */
326623c35297Sanish 	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
326723c35297Sanish }
326823c35297Sanish 
326923c35297Sanish /*
327023c35297Sanish  * Put bridge registers into initial state
327123c35297Sanish  */
327223c35297Sanish static void
pcicfg_setup_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)3273ffb64830SJordan Paige Hendricks pcicfg_setup_bridge(pcicfg_phdl_t *entry, ddi_acc_handle_t handle)
327423c35297Sanish {
327523c35297Sanish 	/*
327623c35297Sanish 	 * The highest bus seen during probing is the max-subordinate bus
327723c35297Sanish 	 */
327823c35297Sanish 	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
327923c35297Sanish 
328023c35297Sanish 	/*
328123c35297Sanish 	 * Reset the secondary bus
328223c35297Sanish 	 */
328323c35297Sanish 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
328423c35297Sanish 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
328523c35297Sanish 	drv_usecwait(1000);
328623c35297Sanish 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
328723c35297Sanish 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
328823c35297Sanish 	drv_usecwait(1000);
328923c35297Sanish 
329023c35297Sanish 	/*
329123c35297Sanish 	 * Program the memory base register with the
329223c35297Sanish 	 * start of the memory range
329323c35297Sanish 	 */
329423c35297Sanish 	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
329523c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
329623c35297Sanish 
329723c35297Sanish 	/*
329823c35297Sanish 	 * Program the I/O base register with the start of the I/O range
329923c35297Sanish 	 */
330023c35297Sanish 	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
330123c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
330223c35297Sanish 	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
330323c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
330423c35297Sanish 
330523c35297Sanish 	/*
330623c35297Sanish 	 * Program the PF memory base register with the start of
330723c35297Sanish 	 * PF memory range
330823c35297Sanish 	 */
330923c35297Sanish 	pci_config_put16(handle, PCI_BCNF_PF_BASE_LOW,
331023c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
331123c35297Sanish 	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH,
331223c35297Sanish 	    PCICFG_HIADDR(entry->pf_memory_last));
331323c35297Sanish 
331423c35297Sanish 	/*
331523c35297Sanish 	 * Clear status bits
331623c35297Sanish 	 */
331723c35297Sanish 	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
331823c35297Sanish 
331923c35297Sanish 	/*
332023c35297Sanish 	 * Needs to be set to this value
332123c35297Sanish 	 */
332223c35297Sanish 	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
332323c35297Sanish 
332423c35297Sanish 	/*
332523c35297Sanish 	 * XXX - may be delay should be used since noone configures
332623c35297Sanish 	 * devices in the interrupt context
332723c35297Sanish 	 */
332823c35297Sanish 	drv_usecwait(pcicfg_sec_reset_delay);	/* 1 sec wait */
332923c35297Sanish }
333023c35297Sanish 
333123c35297Sanish static void
pcicfg_update_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)3332ffb64830SJordan Paige Hendricks pcicfg_update_bridge(pcicfg_phdl_t *entry, ddi_acc_handle_t handle)
333323c35297Sanish {
333423c35297Sanish 	uint_t length;
333523c35297Sanish 
333623c35297Sanish 	/*
333723c35297Sanish 	 * Program the memory limit register with the end of the memory range
333823c35297Sanish 	 */
333923c35297Sanish 
334023c35297Sanish 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
334126947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN));
334223c35297Sanish 
334323c35297Sanish 	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
334423c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
334526947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN))));
334623c35297Sanish 	/*
334723c35297Sanish 	 * Since this is a bridge, the rest of this range will
334823c35297Sanish 	 * be responded to by the bridge.  We have to round up
334923c35297Sanish 	 * so no other device claims it.
335023c35297Sanish 	 */
335126947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN)
335226947304SEvan Yan 	    - entry->memory_last)) > 0) {
335323c35297Sanish 		(void) pcicfg_get_mem(entry, length, NULL);
335426947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (mem)\n", length);
335523c35297Sanish 	}
335623c35297Sanish 
335723c35297Sanish 	/*
335823c35297Sanish 	 * Program the PF memory limit register with the end of the memory range
335923c35297Sanish 	 */
336023c35297Sanish 
336123c35297Sanish 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
336226947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN));
336323c35297Sanish 
336423c35297Sanish 	pci_config_put16(handle, PCI_BCNF_PF_LIMIT_LOW,
336526947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(
336626947304SEvan Yan 	    entry->pf_memory_last, PCICFG_MEMGRAN))));
336726947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, PCICFG_HIADDR(
336826947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN)));
336926947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->pf_memory_last, PCICFG_MEMGRAN)
337026947304SEvan Yan 	    - entry->pf_memory_last)) > 0) {
337123c35297Sanish 		(void) pcicfg_get_pf_mem(entry, length, NULL);
337226947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (PF mem)\n",
337326947304SEvan Yan 		    length);
337423c35297Sanish 	}
337523c35297Sanish 
337623c35297Sanish 	/*
337723c35297Sanish 	 * Program the I/O limit register with the end of the I/O range
337823c35297Sanish 	 */
337923c35297Sanish 	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
338023c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(
338126947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN)))));
338223c35297Sanish 
338326947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, PCICFG_HIWORD(
338426947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN))));
338523c35297Sanish 
338623c35297Sanish 	/*
338723c35297Sanish 	 * Same as above for I/O space. Since this is a
338823c35297Sanish 	 * bridge, the rest of this range will be responded
338923c35297Sanish 	 * to by the bridge.  We have to round up so no
339023c35297Sanish 	 * other device claims it.
339123c35297Sanish 	 */
339226947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN)
339326947304SEvan Yan 	    - entry->io_last)) > 0) {
339423c35297Sanish 		(void) pcicfg_get_io(entry, length, NULL);
339526947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (I/O)\n", length);
339623c35297Sanish 	}
339723c35297Sanish }
339823c35297Sanish 
339923c35297Sanish static int
pcicfg_probe_children(dev_info_t * parent,uint_t bus,uint_t device,uint_t func,uint_t * highest_bus,pcicfg_flags_t flags,boolean_t is_pcie)340026947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
3401c0da6274SZhi-Jun Robin Fu     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
340223c35297Sanish {
340323c35297Sanish 	dev_info_t		*new_child;
340423c35297Sanish 	ddi_acc_handle_t	config_handle;
34055af4ae46Sjveta 	int			ret = PCICFG_FAILURE;
3406*bd97c7ceSRobert Mustacchi 	pci_prop_data_t		prop_data;
3407*bd97c7ceSRobert Mustacchi 	pci_prop_failure_t	prop_ret;
340823c35297Sanish 
340923c35297Sanish 	/*
341023c35297Sanish 	 * This node will be put immediately below
341123c35297Sanish 	 * "parent". Allocate a blank device node.  It will either
341223c35297Sanish 	 * be filled in or freed up based on further probing.
341323c35297Sanish 	 */
341423c35297Sanish 
341523c35297Sanish 	ndi_devi_alloc_sleep(parent, DEVI_PSEUDO_NEXNAME,
341623c35297Sanish 	    (pnode_t)DEVI_SID_NODEID, &new_child);
341723c35297Sanish 
341826947304SEvan Yan 	if (pcicfg_add_config_reg(new_child, bus, device, func)
341926947304SEvan Yan 	    != DDI_SUCCESS) {
342026947304SEvan Yan 		DEBUG0("pcicfg_probe_children():Failed to add candidate REG\n");
342123c35297Sanish 		goto failedconfig;
342223c35297Sanish 	}
342323c35297Sanish 
342423c35297Sanish 	if ((ret = pcicfg_config_setup(new_child, &config_handle))
342523c35297Sanish 	    != PCICFG_SUCCESS) {
342623c35297Sanish 		if (ret == PCICFG_NODEVICE) {
342723c35297Sanish 			(void) ndi_devi_free(new_child);
342823c35297Sanish 			return (ret);
342923c35297Sanish 		}
343023c35297Sanish 		DEBUG0("pcicfg_probe_children():"
343123c35297Sanish 		"Failed to setup config space\n");
343223c35297Sanish 		goto failedconfig;
343323c35297Sanish 	}
343423c35297Sanish 
3435c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3436c0da6274SZhi-Jun Robin Fu 		(void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
3437c0da6274SZhi-Jun Robin Fu 		    PCIE_BUS_INITIAL);
3438c0da6274SZhi-Jun Robin Fu 
343923c35297Sanish 	/*
344023c35297Sanish 	 * As soon as we have access to config space,
344123c35297Sanish 	 * turn off device. It will get turned on
344223c35297Sanish 	 * later (after memory is assigned).
344323c35297Sanish 	 */
344423c35297Sanish 	(void) pcicfg_device_off(config_handle);
344523c35297Sanish 
3446*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_data_fill(config_handle, bus, device, func,
3447*bd97c7ceSRobert Mustacchi 	    &prop_data);
3448*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3449*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to get basic PCI data for "
3450*bd97c7ceSRobert Mustacchi 		    "b/d/f 0x%x/0x%x/0x%x: 0x%x", bus, device, func, prop_ret);
345123c35297Sanish 		goto failedchild;
345223c35297Sanish 	}
345323c35297Sanish 
3454*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_name_node(new_child, &prop_data);
3455*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3456*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to set node name for b/d/f "
3457*bd97c7ceSRobert Mustacchi 		    "0x%x/0x%x/0x%x: 0x%x", bus,
3458*bd97c7ceSRobert Mustacchi 		    device, func, prop_ret);
345923c35297Sanish 		goto failedchild;
346023c35297Sanish 	}
346123c35297Sanish 
3462*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_set_common_props(new_child, &prop_data);
3463*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3464*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to set properties for b/d/f "
3465*bd97c7ceSRobert Mustacchi 		    "0x%x/0x%x/0x%x: 0x%x", bus,
3466*bd97c7ceSRobert Mustacchi 		    device, func, prop_ret);
3467*bd97c7ceSRobert Mustacchi 		goto failedchild;
3468*bd97c7ceSRobert Mustacchi 	}
3469*bd97c7ceSRobert Mustacchi 
3470*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_set_compatible(new_child, &prop_data);
3471*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3472*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to set compatible property "
3473*bd97c7ceSRobert Mustacchi 		    "for b/d/f 0x%x/0x%x/0x%x: 0x%x",
3474*bd97c7ceSRobert Mustacchi 		    bus, device, func, prop_ret);
3475*bd97c7ceSRobert Mustacchi 		goto failedchild;
3476*bd97c7ceSRobert Mustacchi 	}
347723c35297Sanish 
347823c35297Sanish 	/*
347923c35297Sanish 	 * If this is not a multi-function card only probe function zero.
348023c35297Sanish 	 */
3481*bd97c7ceSRobert Mustacchi 	if ((prop_data.ppd_flags & PCI_PROP_F_MULT_FUNC) == 0 && func != 0) {
348223c35297Sanish 
3483c0da6274SZhi-Jun Robin Fu 		ret = PCICFG_NODEVICE;
3484c0da6274SZhi-Jun Robin Fu 		goto failedchild;
348523c35297Sanish 	}
348623c35297Sanish 
348723c35297Sanish 	/*
348823c35297Sanish 	 * Attach the child to its parent
348923c35297Sanish 	 */
349023c35297Sanish 	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
349123c35297Sanish 
34923a634bfcSVikram Hegde 	DEVI_SET_PCI(new_child);
34933a634bfcSVikram Hegde 
3494*bd97c7ceSRobert Mustacchi 	if (prop_data.ppd_header == PCI_HEADER_PPB) {
349523c35297Sanish 
349626947304SEvan Yan 		DEBUG3("--Bridge found bus [0x%x] device[0x%x] func [0x%x]\n",
349726947304SEvan Yan 		    bus, device, func);
349826947304SEvan Yan 
349926947304SEvan Yan 		/* Only support read-only probe for leaf device */
350026947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
350126947304SEvan Yan 			goto failedchild;
350223c35297Sanish 
35035af4ae46Sjveta 		ret = pcicfg_probe_bridge(new_child, config_handle, bus,
3504c0da6274SZhi-Jun Robin Fu 		    highest_bus, is_pcie);
35055af4ae46Sjveta 		if (ret != PCICFG_SUCCESS) {
350623c35297Sanish 			(void) pcicfg_free_bridge_resources(new_child);
350723c35297Sanish 			goto failedchild;
350823c35297Sanish 		}
350923c35297Sanish 
351023c35297Sanish 	} else {
351123c35297Sanish 
351223c35297Sanish 		DEBUG3("--Leaf device found bus [0x%x] device"
351326947304SEvan Yan 		    "[0x%x] func [0x%x]\n", bus, device, func);
351426947304SEvan Yan 
351526947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY) {
351626947304SEvan Yan 			/*
351726947304SEvan Yan 			 * with read-only probe, don't do any resource
351826947304SEvan Yan 			 * allocation, just read the BARs and update props.
351926947304SEvan Yan 			 */
352026947304SEvan Yan 			ret = pcicfg_populate_props_from_bar(new_child,
352126947304SEvan Yan 			    config_handle);
352226947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
352326947304SEvan Yan 				goto failedchild;
352426947304SEvan Yan 
352526947304SEvan Yan 			/*
352626947304SEvan Yan 			 * now allocate the resources, just remove the
352726947304SEvan Yan 			 * resources from the parent busra pool.
352826947304SEvan Yan 			 */
352926947304SEvan Yan 			ret = pcicfg_device_assign_readonly(new_child);
353026947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
353126947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child);
353226947304SEvan Yan 				goto failedchild;
353326947304SEvan Yan 			}
353426947304SEvan Yan 
353526947304SEvan Yan 		} else {
353626947304SEvan Yan 			/*
353726947304SEvan Yan 			 * update "reg" property by sizing the BARs.
353826947304SEvan Yan 			 */
353926947304SEvan Yan 			ret = pcicfg_populate_reg_props(new_child,
354026947304SEvan Yan 			    config_handle);
354126947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
354226947304SEvan Yan 				goto failedchild;
354326947304SEvan Yan 
354426947304SEvan Yan 			/* now allocate & program the resources */
354526947304SEvan Yan 			ret = pcicfg_device_assign(new_child);
354626947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
354726947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child);
354826947304SEvan Yan 				goto failedchild;
354926947304SEvan Yan 			}
355026947304SEvan Yan 		}
355126947304SEvan Yan 
355226947304SEvan Yan 		(void) ndi_devi_bind_driver(new_child, 0);
355326947304SEvan Yan 	}
355426947304SEvan Yan 
355526947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
355626947304SEvan Yan 
3557c0da6274SZhi-Jun Robin Fu 	/*
3558c0da6274SZhi-Jun Robin Fu 	 * Properties have been setted up, so initialize the remaining
3559c0da6274SZhi-Jun Robin Fu 	 * bus_t fields
3560c0da6274SZhi-Jun Robin Fu 	 */
3561c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3562c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
3563c0da6274SZhi-Jun Robin Fu 
356426947304SEvan Yan 	return (PCICFG_SUCCESS);
356526947304SEvan Yan 
356626947304SEvan Yan failedchild:
356726947304SEvan Yan 	/*
356826947304SEvan Yan 	 * XXX check if it should be taken offline (if online)
356926947304SEvan Yan 	 */
357026947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
357126947304SEvan Yan 
3572c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3573c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_FINAL);
3574c0da6274SZhi-Jun Robin Fu 
357526947304SEvan Yan failedconfig:
357626947304SEvan Yan 
357726947304SEvan Yan 	(void) ndi_devi_free(new_child);
357826947304SEvan Yan 	return (ret);
357926947304SEvan Yan }
358026947304SEvan Yan 
358126947304SEvan Yan /*
358226947304SEvan Yan  * Sizing the BARs and update "reg" property
358326947304SEvan Yan  */
358426947304SEvan Yan static int
pcicfg_populate_reg_props(dev_info_t * new_child,ddi_acc_handle_t config_handle)3585ffb64830SJordan Paige Hendricks pcicfg_populate_reg_props(dev_info_t *new_child, ddi_acc_handle_t config_handle)
358626947304SEvan Yan {
358726947304SEvan Yan 	int		i;
358826947304SEvan Yan 	uint32_t	request;
358923c35297Sanish 
359023c35297Sanish 	i = PCI_CONF_BASE0;
359123c35297Sanish 
359223c35297Sanish 	while (i <= PCI_CONF_BASE5) {
359323c35297Sanish 
359423c35297Sanish 		pci_config_put32(config_handle, i, 0xffffffff);
359523c35297Sanish 
359623c35297Sanish 		request = pci_config_get32(config_handle, i);
359723c35297Sanish 		/*
359823c35297Sanish 		 * If its a zero length, don't do
359923c35297Sanish 		 * any programming.
360023c35297Sanish 		 */
360123c35297Sanish 		if (request != 0) {
360223c35297Sanish 			/*
360323c35297Sanish 			 * Add to the "reg" property
360423c35297Sanish 			 */
360523c35297Sanish 			if (pcicfg_update_reg_prop(new_child,
360623c35297Sanish 			    request, i) != PCICFG_SUCCESS) {
360723c35297Sanish 				goto failedchild;
360823c35297Sanish 			}
360923c35297Sanish 		} else {
361023c35297Sanish 			DEBUG1("BASE register [0x%x] asks for "
361123c35297Sanish 			    "[0x0]=[0x0](32)\n", i);
361223c35297Sanish 			i += 4;
361323c35297Sanish 			continue;
361423c35297Sanish 		}
361523c35297Sanish 
361623c35297Sanish 		/*
361723c35297Sanish 		 * Increment by eight if it is 64 bit address space
361823c35297Sanish 		 */
361923c35297Sanish 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
362023c35297Sanish 			DEBUG3("BASE register [0x%x] asks for "
362123c35297Sanish 			    "[0x%x]=[0x%x] (64)\n",
362226947304SEvan Yan 			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362323c35297Sanish 			i += 8;
362423c35297Sanish 		} else {
362523c35297Sanish 			DEBUG3("BASE register [0x%x] asks for "
362623c35297Sanish 			    "[0x%x]=[0x%x](32)\n",
362726947304SEvan Yan 			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362823c35297Sanish 			i += 4;
362923c35297Sanish 		}
363023c35297Sanish 	}
363123c35297Sanish 
363223c35297Sanish 	/*
363323c35297Sanish 	 * Get the ROM size and create register for it
363423c35297Sanish 	 */
363523c35297Sanish 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
363623c35297Sanish 
363723c35297Sanish 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
363823c35297Sanish 	/*
363923c35297Sanish 	 * If its a zero length, don't do
364023c35297Sanish 	 * any programming.
364123c35297Sanish 	 */
364223c35297Sanish 
364323c35297Sanish 	if (request != 0) {
364423c35297Sanish 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
364523c35297Sanish 		    PCI_CONF_ROM, request,
364623c35297Sanish 		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
364723c35297Sanish 		/*
364823c35297Sanish 		 * Add to the "reg" property
364923c35297Sanish 		 */
365026947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
365126947304SEvan Yan 		    != PCICFG_SUCCESS) {
365223c35297Sanish 			goto failedchild;
365323c35297Sanish 		}
365423c35297Sanish 	}
365523c35297Sanish 
365623c35297Sanish 	return (PCICFG_SUCCESS);
365723c35297Sanish 
365823c35297Sanish failedchild:
365926947304SEvan Yan 	return (PCICFG_FAILURE);
366026947304SEvan Yan }
366126947304SEvan Yan 
366223c35297Sanish /*
366326947304SEvan Yan  * Read the BARs and update properties. Used in virtual hotplug.
366423c35297Sanish  */
366526947304SEvan Yan static int
pcicfg_populate_props_from_bar(dev_info_t * new_child,ddi_acc_handle_t config_handle)366626947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child,
366726947304SEvan Yan     ddi_acc_handle_t config_handle)
366826947304SEvan Yan {
366926947304SEvan Yan 	uint32_t request, base, base_hi, size;
367026947304SEvan Yan 	int i;
367123c35297Sanish 
367226947304SEvan Yan 	i = PCI_CONF_BASE0;
367323c35297Sanish 
367426947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
367526947304SEvan Yan 		/*
367626947304SEvan Yan 		 * determine the size of the address space
367726947304SEvan Yan 		 */
367826947304SEvan Yan 		base = pci_config_get32(config_handle, i);
367926947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
368026947304SEvan Yan 		request = pci_config_get32(config_handle, i);
368126947304SEvan Yan 		pci_config_put32(config_handle, i, base);
368226947304SEvan Yan 
368326947304SEvan Yan 		/*
368426947304SEvan Yan 		 * If its a zero length, don't do any programming.
368526947304SEvan Yan 		 */
368626947304SEvan Yan 		if (request != 0) {
368726947304SEvan Yan 			/*
368826947304SEvan Yan 			 * Add to the "reg" property
368926947304SEvan Yan 			 */
369026947304SEvan Yan 			if (pcicfg_update_reg_prop(new_child,
369126947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
369226947304SEvan Yan 				goto failedchild;
369326947304SEvan Yan 			}
369426947304SEvan Yan 
369526947304SEvan Yan 			if ((PCI_BASE_SPACE_IO & request) == 0 &&
369626947304SEvan Yan 			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
369726947304SEvan Yan 				base_hi = pci_config_get32(config_handle, i+4);
369826947304SEvan Yan 			} else {
369926947304SEvan Yan 				base_hi = 0;
370026947304SEvan Yan 			}
370126947304SEvan Yan 			/*
370226947304SEvan Yan 			 * Add to "assigned-addresses" property
370326947304SEvan Yan 			 */
370426947304SEvan Yan 			size = (~(PCI_BASE_M_ADDR_M & request))+1;
370526947304SEvan Yan 			if (pcicfg_update_assigned_prop_value(new_child,
370626947304SEvan Yan 			    size, base, base_hi, i) != PCICFG_SUCCESS) {
370726947304SEvan Yan 				goto failedchild;
370826947304SEvan Yan 			}
370926947304SEvan Yan 		} else {
371026947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for [0x0]=[0x0]"
371126947304SEvan Yan 			    "(32)\n", i);
371226947304SEvan Yan 			i += 4;
371326947304SEvan Yan 			continue;
371426947304SEvan Yan 		}
371526947304SEvan Yan 
371626947304SEvan Yan 		/*
371726947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
371826947304SEvan Yan 		 */
371926947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
372026947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
372126947304SEvan Yan 			    "(64)\n", i, request,
372226947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
372326947304SEvan Yan 			i += 8;
372426947304SEvan Yan 		} else {
372526947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
372626947304SEvan Yan 			    "(32)\n", i, request,
372726947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
372826947304SEvan Yan 			i += 4;
372926947304SEvan Yan 		}
373026947304SEvan Yan 	}
373126947304SEvan Yan 
373226947304SEvan Yan 	/*
373326947304SEvan Yan 	 * Get the ROM size and create register for it
373426947304SEvan Yan 	 */
373526947304SEvan Yan 	base = pci_config_get32(config_handle, PCI_CONF_ROM);
373626947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
373726947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
373826947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, base);
373926947304SEvan Yan 
374026947304SEvan Yan 	/*
374126947304SEvan Yan 	 * If its a zero length, don't do
374226947304SEvan Yan 	 * any programming.
374326947304SEvan Yan 	 */
374426947304SEvan Yan 	if (request != 0) {
374526947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
374626947304SEvan Yan 		    PCI_CONF_ROM, request,
374726947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
374826947304SEvan Yan 		/*
374926947304SEvan Yan 		 * Add to the "reg" property
375026947304SEvan Yan 		 */
375126947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
375226947304SEvan Yan 		    != PCICFG_SUCCESS) {
375326947304SEvan Yan 			goto failedchild;
375426947304SEvan Yan 		}
375526947304SEvan Yan 		/*
375626947304SEvan Yan 		 * Add to "assigned-addresses" property
375726947304SEvan Yan 		 */
375826947304SEvan Yan 		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
375926947304SEvan Yan 		if (pcicfg_update_assigned_prop_value(new_child, size,
376026947304SEvan Yan 		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
376126947304SEvan Yan 			goto failedchild;
376226947304SEvan Yan 		}
376326947304SEvan Yan 	}
376426947304SEvan Yan 
376526947304SEvan Yan 	return (PCICFG_SUCCESS);
376626947304SEvan Yan 
376726947304SEvan Yan failedchild:
376826947304SEvan Yan 	return (PCICFG_FAILURE);
376923c35297Sanish }
377023c35297Sanish 
377123c35297Sanish static int
pcicfg_probe_bridge(dev_info_t * new_child,ddi_acc_handle_t h,uint_t bus,uint_t * highest_bus,boolean_t is_pcie)377223c35297Sanish pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
3773c0da6274SZhi-Jun Robin Fu     uint_t *highest_bus, boolean_t is_pcie)
377423c35297Sanish {
377523c35297Sanish 	uint64_t next_bus;
377623c35297Sanish 	uint_t new_bus, num_slots;
377723c35297Sanish 	ndi_ra_request_t req;
377823c35297Sanish 	int rval, i, j;
377923c35297Sanish 	uint64_t mem_answer, io_answer, mem_base, io_base, mem_alen, io_alen;
378023c35297Sanish 	uint64_t pf_mem_answer, pf_mem_base, pf_mem_alen;
378123c35297Sanish 	uint64_t mem_size, io_size, pf_mem_size;
378223c35297Sanish 	uint64_t mem_end, pf_mem_end, io_end;
378323c35297Sanish 	uint64_t round_answer, round_len;
378423c35297Sanish 	ppb_ranges_t range[PCICFG_RANGE_LEN];
378523c35297Sanish 	int bus_range[2];
378623c35297Sanish 	pcicfg_phdl_t phdl;
378723c35297Sanish 	uint64_t pcibus_base, pcibus_alen;
378823c35297Sanish 	uint64_t max_bus;
378923c35297Sanish 	uint8_t pcie_device_type = 0;
379023c35297Sanish 	uint_t pf_mem_supported = 0;
379126947304SEvan Yan 	dev_info_t *new_device;
379226947304SEvan Yan 	int trans_device;
379326947304SEvan Yan 	int ari_mode = B_FALSE;
379426947304SEvan Yan 	int max_function = PCI_MAX_FUNCTIONS;
379523c35297Sanish 
379623c35297Sanish 	io_answer = io_base = io_alen = io_size = 0;
379723c35297Sanish 	pf_mem_answer = pf_mem_base = pf_mem_size = pf_mem_alen = 0;
379823c35297Sanish 
379923c35297Sanish 	/*
380026947304SEvan Yan 	 * Set "device_type" to "pci", the actual type will be set later
380126947304SEvan Yan 	 * by pcicfg_set_busnode_props() below. This is needed as the
380226947304SEvan Yan 	 * pcicfg_ra_free() below would update "available" property based
380326947304SEvan Yan 	 * on "device_type".
380426947304SEvan Yan 	 *
380526947304SEvan Yan 	 * This code can be removed later after PCI configurator is changed
380626947304SEvan Yan 	 * to use PCIRM, which automatically update properties upon allocation
380726947304SEvan Yan 	 * and free, at that time we'll be able to remove the code inside
380826947304SEvan Yan 	 * ndi_ra_alloc/free() which currently updates "available" property
380926947304SEvan Yan 	 * for pci/pcie devices in pcie fabric.
381026947304SEvan Yan 	 */
381126947304SEvan Yan 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
381226947304SEvan Yan 	    "device_type", "pci") != DDI_SUCCESS) {
381326947304SEvan Yan 		DEBUG0("Failed to set \"device_type\" props\n");
381426947304SEvan Yan 		return (PCICFG_FAILURE);
381526947304SEvan Yan 	}
381626947304SEvan Yan 
381726947304SEvan Yan 	/*
381823c35297Sanish 	 * setup resource maps for the bridge node
381923c35297Sanish 	 */
382023c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
382123c35297Sanish 	    == NDI_FAILURE) {
382223c35297Sanish 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
382323c35297Sanish 		rval = PCICFG_FAILURE;
382423c35297Sanish 		goto cleanup;
382523c35297Sanish 	}
382623c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
382723c35297Sanish 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
382823c35297Sanish 		rval = PCICFG_FAILURE;
382923c35297Sanish 		goto cleanup;
383023c35297Sanish 	}
383123c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
383223c35297Sanish 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
383323c35297Sanish 		rval = PCICFG_FAILURE;
383423c35297Sanish 		goto cleanup;
383523c35297Sanish 	}
383623c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
383723c35297Sanish 	    NDI_FAILURE) {
383823c35297Sanish 		DEBUG0("Can not setup resource map -"
383923c35297Sanish 		    " NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
384023c35297Sanish 		rval = PCICFG_FAILURE;
384123c35297Sanish 		goto cleanup;
384223c35297Sanish 	}
384323c35297Sanish 
384423c35297Sanish 	/*
384523c35297Sanish 	 * Allocate bus range pool for the bridge.
384623c35297Sanish 	 */
384723c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
384823c35297Sanish 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
384923c35297Sanish 	req.ra_boundbase = 0;
385023c35297Sanish 	req.ra_boundlen = req.ra_len = (PCI_MAX_BUS_NUM -1);
385123c35297Sanish 	req.ra_align_mask = 0;  /* no alignment needed */
385223c35297Sanish 
385323c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
385423c35297Sanish 	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
385523c35297Sanish 
385623c35297Sanish 	if (rval != NDI_SUCCESS) {
385723c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
385823c35297Sanish 			/*EMPTY*/
385923c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
386023c35297Sanish 		} else {
386123c35297Sanish 			DEBUG0(
386223c35297Sanish 			    "Failed to allocate bus range for bridge\n");
38635af4ae46Sjveta 			rval = PCICFG_NORESRC;
386423c35297Sanish 			goto cleanup;
386523c35297Sanish 		}
386623c35297Sanish 	}
386723c35297Sanish 
386823c35297Sanish 	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
386923c35297Sanish 	    pcibus_base, pcibus_alen);
387023c35297Sanish 
387123c35297Sanish 	/*
387223c35297Sanish 	 * Put available bus range into the pool.
387323c35297Sanish 	 * Take the first one for this bridge to use and don't give
387423c35297Sanish 	 * to child.
387523c35297Sanish 	 */
387623c35297Sanish 	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
387723c35297Sanish 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
387823c35297Sanish 
387923c35297Sanish 	next_bus = pcibus_base;
388023c35297Sanish 	max_bus = pcibus_base + pcibus_alen - 1;
388123c35297Sanish 
388223c35297Sanish 	new_bus = next_bus;
388323c35297Sanish 
388423c35297Sanish 	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
388523c35297Sanish 
388623c35297Sanish 	/* Keep track of highest bus for subordinate bus programming */
388723c35297Sanish 	*highest_bus = new_bus;
388823c35297Sanish 
388923c35297Sanish 	/*
389023c35297Sanish 	 * Allocate (non-prefetchable) Memory Space for Bridge
389123c35297Sanish 	 */
389223c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
389323c35297Sanish 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
389423c35297Sanish 	req.ra_boundbase = 0;
389523c35297Sanish 	/*
389623c35297Sanish 	 * limit the boundlen,len to a 32b quantity. It should be Ok to
389723c35297Sanish 	 * lose alignment-based-size of resource due to this.
389823c35297Sanish 	 */
389923c35297Sanish 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
390023c35297Sanish 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
390123c35297Sanish 	req.ra_align_mask =
390223c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
390323c35297Sanish 
390423c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
390523c35297Sanish 	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
390623c35297Sanish 
390723c35297Sanish 	if (rval != NDI_SUCCESS) {
390823c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
390923c35297Sanish 			/*EMPTY*/
391023c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
391123c35297Sanish 		} else {
391223c35297Sanish 			DEBUG0(
391323c35297Sanish 			    "Failed to allocate memory for bridge\n");
39145af4ae46Sjveta 			rval = PCICFG_NORESRC;
391523c35297Sanish 			goto cleanup;
391623c35297Sanish 		}
391723c35297Sanish 	}
391823c35297Sanish 
391923c35297Sanish 	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
392023c35297Sanish 	    PCICFG_HIADDR(mem_answer),
392123c35297Sanish 	    PCICFG_LOADDR(mem_answer),
392223c35297Sanish 	    mem_alen);
392323c35297Sanish 
392423c35297Sanish 	/*
392523c35297Sanish 	 * Put available memory into the pool.
392623c35297Sanish 	 */
392723c35297Sanish 	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
392823c35297Sanish 	    NDI_RA_PASS);
392923c35297Sanish 
393023c35297Sanish 	mem_base = mem_answer;
393123c35297Sanish 
393223c35297Sanish 	/*
393323c35297Sanish 	 * Allocate I/O Space for Bridge
393423c35297Sanish 	 */
393523c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
393623c35297Sanish 	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
393723c35297Sanish 	req.ra_boundbase = 0;
393823c35297Sanish 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
393923c35297Sanish 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
394023c35297Sanish 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
394123c35297Sanish 
394223c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
394323c35297Sanish 	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
394423c35297Sanish 
394523c35297Sanish 	if (rval != NDI_SUCCESS) {
394623c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
394723c35297Sanish 			/*EMPTY*/
394823c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
394923c35297Sanish 		} else {
395023c35297Sanish 			DEBUG0("Failed to allocate io space for bridge\n");
395123c35297Sanish 			/* i/o space is an optional requirement so continue */
395223c35297Sanish 		}
395323c35297Sanish 	}
395423c35297Sanish 
395523c35297Sanish 	DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
395623c35297Sanish 	    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), io_alen);
395723c35297Sanish 
395823c35297Sanish 	/*
395923c35297Sanish 	 * Put available I/O into the pool.
396023c35297Sanish 	 */
396123c35297Sanish 	(void) ndi_ra_free(new_child, io_answer, io_alen, NDI_RA_TYPE_IO,
396223c35297Sanish 	    NDI_RA_PASS);
396323c35297Sanish 
396423c35297Sanish 	io_base = io_answer;
396523c35297Sanish 
396623c35297Sanish 	/*
396723c35297Sanish 	 * Check if the bridge supports Prefetchable memory range.
396823c35297Sanish 	 * If it does, then we setup PF memory range for the bridge.
396923c35297Sanish 	 * Otherwise, we skip the step of setting up PF memory
397023c35297Sanish 	 * range for it. This could cause config operation to
397123c35297Sanish 	 * fail if any devices under the bridge need PF memory.
397223c35297Sanish 	 */
397323c35297Sanish 	/* write a non zero value to the PF BASE register */
397423c35297Sanish 	pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
397523c35297Sanish 	/* if the read returns zero then PF range is not supported */
397623c35297Sanish 	if (pci_config_get16(h, PCI_BCNF_PF_BASE_LOW) == 0) {
397723c35297Sanish 		/* bridge doesn't support PF memory range */
397823c35297Sanish 		goto pf_setup_end;
397923c35297Sanish 	} else {
398023c35297Sanish 		pf_mem_supported = 1;
398123c35297Sanish 		/* reset the PF BASE register */
398223c35297Sanish 		pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0);
398323c35297Sanish 	}
398423c35297Sanish 
398523c35297Sanish 	/*
398623c35297Sanish 	 * Bridge supports PF mem range; Allocate PF Memory Space for it.
398723c35297Sanish 	 *
398823c35297Sanish 	 * Note: Both non-prefetchable and prefetchable memory space
398923c35297Sanish 	 * allocations are made within 32bit space. Currently, BIOSs
399023c35297Sanish 	 * allocate device memory for PCI devices within the 32bit space
399123c35297Sanish 	 * so this will not be a problem.
399223c35297Sanish 	 */
399323c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
399423c35297Sanish 	req.ra_flags = NDI_RA_ALLOC_PARTIAL_OK | NDI_RA_ALLOC_BOUNDED;
399523c35297Sanish 	req.ra_boundbase = 0;
399623c35297Sanish 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
399723c35297Sanish 	req.ra_align_mask =
399823c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
399923c35297Sanish 
400023c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
400123c35297Sanish 	    &pf_mem_answer, &pf_mem_alen,  NDI_RA_TYPE_PCI_PREFETCH_MEM,
400223c35297Sanish 	    NDI_RA_PASS);
400323c35297Sanish 
400423c35297Sanish 	if (rval != NDI_SUCCESS) {
400523c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
400623c35297Sanish 			/*EMPTY*/
400723c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
400823c35297Sanish 		} else {
400923c35297Sanish 			DEBUG0(
401023c35297Sanish 			    "Failed to allocate PF memory for bridge\n");
401123c35297Sanish 			/* PF mem is an optional requirement so continue */
401223c35297Sanish 		}
401323c35297Sanish 	}
401423c35297Sanish 
401523c35297Sanish 	DEBUG3("Bridge PF Memory Allocated [0x%x.%x] len [0x%x]\n",
401623c35297Sanish 	    PCICFG_HIADDR(pf_mem_answer),
401723c35297Sanish 	    PCICFG_LOADDR(pf_mem_answer),
401823c35297Sanish 	    pf_mem_alen);
401923c35297Sanish 
402023c35297Sanish 	/*
402123c35297Sanish 	 * Put available PF memory into the pool.
402223c35297Sanish 	 */
402323c35297Sanish 	(void) ndi_ra_free(new_child, pf_mem_answer, pf_mem_alen,
402423c35297Sanish 	    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
402523c35297Sanish 
402623c35297Sanish 	pf_mem_base = pf_mem_answer;
402723c35297Sanish 
402823c35297Sanish 	/*
402923c35297Sanish 	 * Program the PF memory base register with the
403023c35297Sanish 	 * start of the memory range
403123c35297Sanish 	 */
403223c35297Sanish 	pci_config_put16(h, PCI_BCNF_PF_BASE_LOW,
403323c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_answer)));
403423c35297Sanish 	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH,
403523c35297Sanish 	    PCICFG_HIADDR(pf_mem_answer));
403623c35297Sanish 
403723c35297Sanish 	/*
403823c35297Sanish 	 * Program the PF memory limit register with the
403923c35297Sanish 	 * end of the memory range.
404023c35297Sanish 	 */
404123c35297Sanish 	pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
404223c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
404323c35297Sanish 	    PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
404423c35297Sanish 	    PCICFG_MEMGRAN) - 1)));
404523c35297Sanish 	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
404623c35297Sanish 	    PCICFG_HIADDR(PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
404723c35297Sanish 	    PCICFG_MEMGRAN) - 1));
404823c35297Sanish 
404923c35297Sanish 	/*
405023c35297Sanish 	 * Allocate the chunk of PF memory (if any) not programmed into the
405123c35297Sanish 	 * bridge because of the round down.
405223c35297Sanish 	 */
405323c35297Sanish 	if (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen), PCICFG_MEMGRAN)
405423c35297Sanish 	    != (pf_mem_answer + pf_mem_alen)) {
405523c35297Sanish 		DEBUG0("Need to allocate Memory round off chunk\n");
405623c35297Sanish 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
405723c35297Sanish 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
405823c35297Sanish 		req.ra_addr = PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
405923c35297Sanish 		    PCICFG_MEMGRAN);
406023c35297Sanish 		req.ra_len =  (pf_mem_answer + pf_mem_alen) -
406123c35297Sanish 		    (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
406223c35297Sanish 		    PCICFG_MEMGRAN));
406323c35297Sanish 
406423c35297Sanish 		(void) ndi_ra_alloc(new_child, &req,
406523c35297Sanish 		    &round_answer, &round_len,  NDI_RA_TYPE_PCI_PREFETCH_MEM,
406623c35297Sanish 		    NDI_RA_PASS);
406723c35297Sanish 	}
406823c35297Sanish 
406923c35297Sanish pf_setup_end:
407023c35297Sanish 
407123c35297Sanish 	/*
407223c35297Sanish 	 * Program the memory base register with the
407323c35297Sanish 	 * start of the memory range
407423c35297Sanish 	 */
407523c35297Sanish 	pci_config_put16(h, PCI_BCNF_MEM_BASE,
407623c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
407723c35297Sanish 
407823c35297Sanish 	/*
407923c35297Sanish 	 * Program the memory limit register with the
408023c35297Sanish 	 * end of the memory range.
408123c35297Sanish 	 */
408223c35297Sanish 
408323c35297Sanish 	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
408423c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
408523c35297Sanish 	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
408623c35297Sanish 
408723c35297Sanish 	/*
408823c35297Sanish 	 * Allocate the chunk of memory (if any) not programmed into the
408923c35297Sanish 	 * bridge because of the round down.
409023c35297Sanish 	 */
409123c35297Sanish 	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
409223c35297Sanish 	    != (mem_answer + mem_alen)) {
409323c35297Sanish 		DEBUG0("Need to allocate Memory round off chunk\n");
409423c35297Sanish 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
409523c35297Sanish 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
409623c35297Sanish 		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
409723c35297Sanish 		    PCICFG_MEMGRAN);
409823c35297Sanish 		req.ra_len =  (mem_answer + mem_alen) -
409923c35297Sanish 		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
410023c35297Sanish 		    PCICFG_MEMGRAN));
410123c35297Sanish 
410223c35297Sanish 		(void) ndi_ra_alloc(new_child, &req,
410323c35297Sanish 		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
410423c35297Sanish 	}
410523c35297Sanish 
410623c35297Sanish 	/*
410723c35297Sanish 	 * Program the I/O Space Base
410823c35297Sanish 	 */
410923c35297Sanish 	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
411023c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(
411123c35297Sanish 	    PCICFG_LOADDR(io_answer))));
411223c35297Sanish 
411323c35297Sanish 	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
411423c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
411523c35297Sanish 
411623c35297Sanish 	/*
411723c35297Sanish 	 * Program the I/O Space Limit
411823c35297Sanish 	 */
411923c35297Sanish 	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
412023c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(
412123c35297Sanish 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
412223c35297Sanish 	    PCICFG_IOGRAN)))) - 1);
412323c35297Sanish 
412423c35297Sanish 	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
412523c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
412623c35297Sanish 	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
412723c35297Sanish 	    - 1);
412823c35297Sanish 
412923c35297Sanish 	/*
413023c35297Sanish 	 * Allocate the chunk of I/O (if any) not programmed into the
413123c35297Sanish 	 * bridge because of the round down.
413223c35297Sanish 	 */
413323c35297Sanish 	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
413423c35297Sanish 	    != (io_answer + io_alen)) {
413523c35297Sanish 		DEBUG0("Need to allocate I/O round off chunk\n");
413623c35297Sanish 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
413723c35297Sanish 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
413823c35297Sanish 		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
413923c35297Sanish 		    PCICFG_IOGRAN);
414023c35297Sanish 		req.ra_len =  (io_answer + io_alen) -
414123c35297Sanish 		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
414223c35297Sanish 		    PCICFG_IOGRAN));
414323c35297Sanish 
414423c35297Sanish 		(void) ndi_ra_alloc(new_child, &req,
414523c35297Sanish 		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
414623c35297Sanish 	}
414723c35297Sanish 
414823c35297Sanish 	(void) pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
414923c35297Sanish 
415023c35297Sanish 	/*
41513f9ec228SZhi-Jun Robin Fu 	 * Setup "ranges" and "bus-range" properties before onlining
41523f9ec228SZhi-Jun Robin Fu 	 * the bridge.
41533f9ec228SZhi-Jun Robin Fu 	 */
41543f9ec228SZhi-Jun Robin Fu 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
41553f9ec228SZhi-Jun Robin Fu 
41563f9ec228SZhi-Jun Robin Fu 	range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
41573f9ec228SZhi-Jun Robin Fu 	    PCI_ADDR_IO);
41583f9ec228SZhi-Jun Robin Fu 	range[0].child_low = range[0].parent_low = io_base;
41593f9ec228SZhi-Jun Robin Fu 	range[1].child_high = range[1].parent_high |=
41603f9ec228SZhi-Jun Robin Fu 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
41613f9ec228SZhi-Jun Robin Fu 	range[1].child_low = range[1].parent_low = mem_base;
41623f9ec228SZhi-Jun Robin Fu 	range[2].child_high = range[2].parent_high |=
41633f9ec228SZhi-Jun Robin Fu 	    (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
41643f9ec228SZhi-Jun Robin Fu 	range[2].child_low = range[2].parent_low = pf_mem_base;
41653f9ec228SZhi-Jun Robin Fu 
41663f9ec228SZhi-Jun Robin Fu 	range[0].size_low = io_alen;
41673f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[0]);
41683f9ec228SZhi-Jun Robin Fu 	range[1].size_low = mem_alen;
41693f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[1]);
41703f9ec228SZhi-Jun Robin Fu 	range[2].size_low = pf_mem_alen;
41713f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[2]);
41723f9ec228SZhi-Jun Robin Fu 
41733f9ec228SZhi-Jun Robin Fu 	bus_range[0] = new_bus;
41743f9ec228SZhi-Jun Robin Fu 	bus_range[1] = max_bus;
41753f9ec228SZhi-Jun Robin Fu 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
41763f9ec228SZhi-Jun Robin Fu 	    "bus-range", bus_range, 2);
41773f9ec228SZhi-Jun Robin Fu 
41783f9ec228SZhi-Jun Robin Fu 	/*
417923c35297Sanish 	 * Reset the secondary bus
418023c35297Sanish 	 */
418123c35297Sanish 	pci_config_put16(h, PCI_BCNF_BCNTRL,
418223c35297Sanish 	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
418323c35297Sanish 
418423c35297Sanish 	drv_usecwait(100);
418523c35297Sanish 
418623c35297Sanish 	pci_config_put16(h, PCI_BCNF_BCNTRL,
418723c35297Sanish 	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
418823c35297Sanish 
418923c35297Sanish 	/*
419023c35297Sanish 	 * Clear status bits
419123c35297Sanish 	 */
419223c35297Sanish 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
419323c35297Sanish 
419423c35297Sanish 	/*
419523c35297Sanish 	 * Needs to be set to this value
419623c35297Sanish 	 */
419723c35297Sanish 	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
419823c35297Sanish 
419923c35297Sanish 	/* check our device_type as defined by Open Firmware */
420023c35297Sanish 	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
420123c35297Sanish 		pcie_device_type = 1;
420223c35297Sanish 
420323c35297Sanish 	/*
420423c35297Sanish 	 * Set bus properties
420523c35297Sanish 	 */
420623c35297Sanish 	if (pcicfg_set_busnode_props(new_child, pcie_device_type)
420723c35297Sanish 	    != PCICFG_SUCCESS) {
420823c35297Sanish 		DEBUG0("Failed to set busnode props\n");
420923c35297Sanish 		rval = PCICFG_FAILURE;
421023c35297Sanish 		goto cleanup;
421123c35297Sanish 	}
421223c35297Sanish 
421323c35297Sanish 	(void) pcicfg_device_on(h);
421423c35297Sanish 
4215c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4216c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
421723c35297Sanish 	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
421823c35297Sanish 	    != NDI_SUCCESS) {
421923c35297Sanish 		DEBUG0("Unable to online bridge\n");
422023c35297Sanish 		rval = PCICFG_FAILURE;
422123c35297Sanish 		goto cleanup;
422223c35297Sanish 	}
422323c35297Sanish 
422423c35297Sanish 	DEBUG0("Bridge is ONLINE\n");
422523c35297Sanish 
422623c35297Sanish 	/*
422723c35297Sanish 	 * After a Reset, we need to wait 2^25 clock cycles before the
422823c35297Sanish 	 * first Configuration access.  The worst case is 33MHz, which
422923c35297Sanish 	 * is a 1 second wait.
423023c35297Sanish 	 */
423123c35297Sanish 	drv_usecwait(pcicfg_sec_reset_delay);
423223c35297Sanish 
423323c35297Sanish 	/*
423423c35297Sanish 	 * Probe all children devices
423523c35297Sanish 	 */
423623c35297Sanish 	DEBUG0("Bridge Programming Complete - probe children\n");
42373fe80ca4SDan Cross 	ndi_devi_enter(new_child);
423826947304SEvan Yan 	for (i = 0; ((i < PCI_MAX_DEVICES) && (ari_mode == B_FALSE));
423926947304SEvan Yan 	    i++) {
424026947304SEvan Yan 		for (j = 0; j < max_function; ) {
424126947304SEvan Yan 			if (ari_mode)
424226947304SEvan Yan 				trans_device = j >> 3;
424326947304SEvan Yan 			else
424426947304SEvan Yan 				trans_device = i;
424526947304SEvan Yan 
424623c35297Sanish 			if ((rval = pcicfg_probe_children(new_child,
4247c0da6274SZhi-Jun Robin Fu 			    new_bus, trans_device, j & 7, highest_bus,
4248c0da6274SZhi-Jun Robin Fu 			    0, is_pcie)) != PCICFG_SUCCESS) {
424923c35297Sanish 				if (rval == PCICFG_NODEVICE) {
425023c35297Sanish 					DEBUG3("No Device at bus [0x%x]"
425123c35297Sanish 					    "device [0x%x] "
425226947304SEvan Yan 					    "func [0x%x]\n", new_bus,
425326947304SEvan Yan 					    trans_device, j & 7);
425426947304SEvan Yan 
425523c35297Sanish 					if (j)
425626947304SEvan Yan 						goto next;
425723c35297Sanish 				} else
425823c35297Sanish 					/*EMPTY*/
425923c35297Sanish 					DEBUG3("Failed to configure bus "
426023c35297Sanish 					    "[0x%x] device [0x%x] "
426126947304SEvan Yan 					    "func [0x%x]\n", new_bus,
426226947304SEvan Yan 					    trans_device, j & 7);
426323c35297Sanish 				break;
426423c35297Sanish 			}
426526947304SEvan Yan next:
426626947304SEvan Yan 			new_device = pcicfg_devi_find(new_child, trans_device,
426726947304SEvan Yan 			    (j & 7));
426826947304SEvan Yan 
426926947304SEvan Yan 			/*
427026947304SEvan Yan 			 * Determine if ARI Forwarding should be enabled.
427126947304SEvan Yan 			 */
427226947304SEvan Yan 			if (j == 0) {
427326947304SEvan Yan 				if (new_device == NULL)
427426947304SEvan Yan 					break;
427526947304SEvan Yan 
427626947304SEvan Yan 				if ((pcie_ari_supported(new_child) ==
427726947304SEvan Yan 				    PCIE_ARI_FORW_SUPPORTED) &&
427826947304SEvan Yan 				    (pcie_ari_device(new_device) ==
427926947304SEvan Yan 				    PCIE_ARI_DEVICE)) {
428026947304SEvan Yan 					if (pcie_ari_enable(new_child) ==
428126947304SEvan Yan 					    DDI_SUCCESS) {
428226947304SEvan Yan 						(void) ddi_prop_create(
428326947304SEvan Yan 						    DDI_DEV_T_NONE,
428426947304SEvan Yan 						    new_child,
428526947304SEvan Yan 						    DDI_PROP_CANSLEEP,
428626947304SEvan Yan 						    "ari-enabled", NULL, 0);
428726947304SEvan Yan 						ari_mode = B_TRUE;
428826947304SEvan Yan 						max_function =
428926947304SEvan Yan 						    PCICFG_MAX_ARI_FUNCTION;
429026947304SEvan Yan 					}
429126947304SEvan Yan 				}
429226947304SEvan Yan 			}
429326947304SEvan Yan 			if (ari_mode == B_TRUE) {
429426947304SEvan Yan 				int next_function;
429526947304SEvan Yan 
429626947304SEvan Yan 				if (new_device == NULL)
429726947304SEvan Yan 					break;
429826947304SEvan Yan 
429926947304SEvan Yan 				if (pcie_ari_get_next_function(new_device,
430026947304SEvan Yan 				    &next_function) != DDI_SUCCESS)
430126947304SEvan Yan 					break;
430226947304SEvan Yan 
430326947304SEvan Yan 				j = next_function;
430426947304SEvan Yan 
430526947304SEvan Yan 				if (next_function == 0)
430626947304SEvan Yan 					break;
430726947304SEvan Yan 			} else
430826947304SEvan Yan 				j++;
430926947304SEvan Yan 
431023c35297Sanish 		}
431123c35297Sanish 		/* if any function fails to be configured, no need to proceed */
431223c35297Sanish 		if (rval != PCICFG_NODEVICE)
431323c35297Sanish 			break;
431423c35297Sanish 	}
43153fe80ca4SDan Cross 	ndi_devi_exit(new_child);
431623c35297Sanish 
431723c35297Sanish 	/*
431823c35297Sanish 	 * Offline the bridge to allow reprogramming of resources.
431926947304SEvan Yan 	 *
432026947304SEvan Yan 	 * This should always succeed since nobody else has started to
432126947304SEvan Yan 	 * use it yet, failing to detach the driver would indicate a bug.
432226947304SEvan Yan 	 * Also in that case it's better just panic than allowing the
432326947304SEvan Yan 	 * configurator to proceed with BAR reprogramming without bridge
432426947304SEvan Yan 	 * driver detached.
432523c35297Sanish 	 */
432626947304SEvan Yan 	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
432726947304SEvan Yan 	    == NDI_SUCCESS);
4328c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4329c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
433023c35297Sanish 
433123c35297Sanish 	phdl.dip = new_child;
433223c35297Sanish 	phdl.memory_base = mem_answer;
433323c35297Sanish 	phdl.io_base = io_answer;
433423c35297Sanish 	phdl.pf_memory_base = pf_mem_answer;
433523c35297Sanish 	phdl.error = PCICFG_SUCCESS;	/* in case of empty child tree */
433623c35297Sanish 
43373fe80ca4SDan Cross 	ndi_devi_enter(ddi_get_parent(new_child));
433823c35297Sanish 	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
43393fe80ca4SDan Cross 	ndi_devi_exit(ddi_get_parent(new_child));
434023c35297Sanish 
434123c35297Sanish 	num_slots = pcicfg_get_nslots(new_child, h);
434223c35297Sanish 	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
434323c35297Sanish 	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
434423c35297Sanish 	pf_mem_end = PCICFG_ROUND_UP(phdl.pf_memory_base, PCICFG_MEMGRAN);
434523c35297Sanish 
434626947304SEvan Yan 	DEBUG4("Start of Unallocated Bridge(%d slots) Resources Mem=0x%lx "
434726947304SEvan Yan 	    "I/O=0x%lx PF_mem=%x%lx\n", num_slots, mem_end, io_end, pf_mem_end);
434823c35297Sanish 
434923c35297Sanish 	/*
435026947304SEvan Yan 	 * Before probing the children we've allocated maximum MEM/IO
435126947304SEvan Yan 	 * resources from parent, and updated "available" property
435226947304SEvan Yan 	 * accordingly. Later we'll be giving up unused resources to
435326947304SEvan Yan 	 * the parent, thus we need to destroy "available" property
435426947304SEvan Yan 	 * here otherwise it will be out-of-sync with the actual free
435526947304SEvan Yan 	 * resources this bridge has. This property will be rebuilt below
435626947304SEvan Yan 	 * with the actual free resources reserved for hotplug slots
435726947304SEvan Yan 	 * (if any).
435826947304SEvan Yan 	 */
435926947304SEvan Yan 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
436026947304SEvan Yan 	/*
436123c35297Sanish 	 * if the bridge a slots, then preallocate. If not, assume static
436223c35297Sanish 	 * configuration. Also check for preallocation limits and spit
436323c35297Sanish 	 * warning messages appropriately (perhaps some can be in debug mode).
436423c35297Sanish 	 */
436523c35297Sanish 	if (num_slots) {
436626947304SEvan Yan 		uint64_t mem_reqd = mem_answer +
436726947304SEvan Yan 		    (num_slots * pcicfg_slot_memsize);
436826947304SEvan Yan 		uint64_t io_reqd = io_answer +
436926947304SEvan Yan 		    (num_slots * pcicfg_slot_iosize);
437026947304SEvan Yan 		uint64_t pf_mem_reqd = pf_mem_answer +
437126947304SEvan Yan 		    (num_slots * pcicfg_slot_pf_memsize);
437226947304SEvan Yan 		uint8_t highest_bus_reqd = new_bus +
437326947304SEvan Yan 		    (num_slots * pcicfg_slot_busnums);
4374949b8557Sarutz #ifdef DEBUG
437523c35297Sanish 		if (mem_end > mem_reqd)
4376949b8557Sarutz 			DEBUG3("Memory space consumed by bridge more "
437723c35297Sanish 			    "than planned for %d slot(s)(%" PRIx64 ",%"
437823c35297Sanish 			    PRIx64 ")", num_slots, mem_answer, mem_end);
437923c35297Sanish 		if (io_end > io_reqd)
4380949b8557Sarutz 			DEBUG3("IO space consumed by bridge more than"
438123c35297Sanish 			    " planned for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
438223c35297Sanish 			    num_slots, io_answer, io_end);
438323c35297Sanish 		if (pf_mem_end > pf_mem_reqd)
4384949b8557Sarutz 			DEBUG3("PF Memory space consumed by bridge"
438523c35297Sanish 			    " more than planned for %d slot(s)(%" PRIx64 ",%"
438623c35297Sanish 			    PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
438723c35297Sanish 		if (*highest_bus > highest_bus_reqd)
4388949b8557Sarutz 			DEBUG3("Buses consumed by bridge more "
438923c35297Sanish 			    "than planned for %d slot(s)(%x, %x)",
439023c35297Sanish 			    num_slots, new_bus, *highest_bus);
439123c35297Sanish 
439223c35297Sanish 		if (mem_reqd > (mem_answer + mem_alen))
4393949b8557Sarutz 			DEBUG3("Memory space required by bridge more "
439423c35297Sanish 			    "than available for %d slot(s)(%" PRIx64 ",%"
439523c35297Sanish 			    PRIx64 ")", num_slots, mem_answer, mem_end);
439623c35297Sanish 		if (io_reqd > (io_answer + io_alen))
4397949b8557Sarutz 			DEBUG3("IO space required by bridge more than"
439823c35297Sanish 			    "available for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
439923c35297Sanish 			    num_slots, io_answer, io_end);
440023c35297Sanish 		if (pf_mem_reqd > (pf_mem_answer + pf_mem_alen))
4401949b8557Sarutz 			DEBUG3("PF Memory space required by bridge"
440223c35297Sanish 			    " more than available for %d slot(s)(%" PRIx64 ",%"
440323c35297Sanish 			    PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
440423c35297Sanish 		if (highest_bus_reqd > max_bus)
4405949b8557Sarutz 			DEBUG3("Bus numbers required by bridge more "
440623c35297Sanish 			    "than available for %d slot(s)(%x, %x)",
440723c35297Sanish 			    num_slots, new_bus, *highest_bus);
4408949b8557Sarutz #endif
440923c35297Sanish 		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
441023c35297Sanish 		    mem_end);
441123c35297Sanish 		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
441223c35297Sanish 		pf_mem_end = MAX((MIN(pf_mem_reqd, (pf_mem_answer +
441323c35297Sanish 		    pf_mem_alen))), pf_mem_end);
441423c35297Sanish 		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
441523c35297Sanish 		    *highest_bus);
441623c35297Sanish 		DEBUG4("mem_end %lx, io_end %lx, pf_mem_end %lx"
441726947304SEvan Yan 		    " highest_bus %x\n", mem_end, io_end, pf_mem_end,
441826947304SEvan Yan 		    *highest_bus);
441923c35297Sanish 	}
442023c35297Sanish 
442123c35297Sanish 	/*
442223c35297Sanish 	 * Give back unused memory space to parent.
442323c35297Sanish 	 */
442426947304SEvan Yan 	(void) ndi_ra_free(ddi_get_parent(new_child), mem_end,
442526947304SEvan Yan 	    (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, NDI_RA_PASS);
442623c35297Sanish 
442723c35297Sanish 	if (mem_end == mem_answer) {
442823c35297Sanish 		DEBUG0("No memory resources used\n");
442923c35297Sanish 		/*
443023c35297Sanish 		 * To prevent the bridge from forwarding any Memory
443123c35297Sanish 		 * transactions, the Memory Limit will be programmed
443223c35297Sanish 		 * with a smaller value than the Memory Base.
443323c35297Sanish 		 */
443423c35297Sanish 		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
443523c35297Sanish 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
443623c35297Sanish 
443723c35297Sanish 		mem_size = 0;
443823c35297Sanish 	} else {
443923c35297Sanish 		/*
444023c35297Sanish 		 * Reprogram the end of the memory.
444123c35297Sanish 		 */
444223c35297Sanish 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
444323c35297Sanish 		    PCICFG_HIWORD(mem_end) - 1);
444423c35297Sanish 		mem_size = mem_end - mem_base;
444523c35297Sanish 	}
444623c35297Sanish 
444723c35297Sanish 	/*
444823c35297Sanish 	 * Give back unused io space to parent.
444923c35297Sanish 	 */
445023c35297Sanish 	(void) ndi_ra_free(ddi_get_parent(new_child),
445123c35297Sanish 	    io_end, (io_answer + io_alen) - io_end,
445223c35297Sanish 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
445323c35297Sanish 
445423c35297Sanish 	if (io_end == io_answer) {
445523c35297Sanish 		DEBUG0("No IO Space resources used\n");
445623c35297Sanish 
445723c35297Sanish 		/*
445823c35297Sanish 		 * To prevent the bridge from forwarding any I/O
445923c35297Sanish 		 * transactions, the I/O Limit will be programmed
446023c35297Sanish 		 * with a smaller value than the I/O Base.
446123c35297Sanish 		 */
446223c35297Sanish 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
446323c35297Sanish 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
446423c35297Sanish 		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
446523c35297Sanish 		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
446623c35297Sanish 
446723c35297Sanish 		io_size = 0;
446823c35297Sanish 	} else {
446923c35297Sanish 		/*
447023c35297Sanish 		 * Reprogram the end of the io space.
447123c35297Sanish 		 */
447223c35297Sanish 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
447323c35297Sanish 		    PCICFG_HIBYTE(PCICFG_LOWORD(
447423c35297Sanish 		    PCICFG_LOADDR(io_end) - 1)));
447523c35297Sanish 
447623c35297Sanish 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
447723c35297Sanish 		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
447823c35297Sanish 
447923c35297Sanish 		io_size = io_end - io_base;
448023c35297Sanish 	}
448123c35297Sanish 
448223c35297Sanish 	/*
448323c35297Sanish 	 * Give back unused PF memory space to parent.
448423c35297Sanish 	 */
448523c35297Sanish 	if (pf_mem_supported) {
448623c35297Sanish 		(void) ndi_ra_free(ddi_get_parent(new_child),
448723c35297Sanish 		    pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
448823c35297Sanish 		    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
448923c35297Sanish 
449023c35297Sanish 		if (pf_mem_end == pf_mem_answer) {
449123c35297Sanish 			DEBUG0("No PF memory resources used\n");
449223c35297Sanish 			/*
449323c35297Sanish 			 * To prevent the bridge from forwarding any PF Memory
449423c35297Sanish 			 * transactions, the PF Memory Limit will be programmed
449523c35297Sanish 			 * with a smaller value than the Memory Base.
449623c35297Sanish 			 */
449723c35297Sanish 			pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
449823c35297Sanish 			pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
449923c35297Sanish 			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
450023c35297Sanish 			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
450123c35297Sanish 
450223c35297Sanish 			pf_mem_size = 0;
450323c35297Sanish 		} else {
450423c35297Sanish 			/*
450523c35297Sanish 			 * Reprogram the end of the PF memory range.
450623c35297Sanish 			 */
450723c35297Sanish 			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
450823c35297Sanish 			    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
450923c35297Sanish 			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
451023c35297Sanish 			    PCICFG_HIADDR(pf_mem_end - 1));
451123c35297Sanish 			pf_mem_size = pf_mem_end - pf_mem_base;
451223c35297Sanish 		}
451323c35297Sanish 	}
451423c35297Sanish 
451523c35297Sanish 	if ((max_bus - *highest_bus) > 0) {
451623c35297Sanish 		/*
451723c35297Sanish 		 * Give back unused bus numbers
451823c35297Sanish 		 */
451923c35297Sanish 		(void) ndi_ra_free(ddi_get_parent(new_child),
452023c35297Sanish 		    *highest_bus+1, max_bus - *highest_bus,
452123c35297Sanish 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
452223c35297Sanish 	}
452323c35297Sanish 
452423c35297Sanish 	/*
452523c35297Sanish 	 * Set bus numbers to ranges encountered during scan
452623c35297Sanish 	 */
452723c35297Sanish 	(void) pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
452823c35297Sanish 
452923c35297Sanish 	/*
453023c35297Sanish 	 * Remove the ranges property if it exists since we will create
453123c35297Sanish 	 * a new one.
453223c35297Sanish 	 */
453323c35297Sanish 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
453423c35297Sanish 
453523c35297Sanish 	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
453623c35297Sanish 	    mem_base, mem_size);
453723c35297Sanish 	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
453823c35297Sanish 	    io_base, io_size);
453923c35297Sanish 	DEBUG2("                         - PF Mem address %lx PF Mem Size %x\n",
454023c35297Sanish 	    pf_mem_base, pf_mem_size);
454123c35297Sanish 
454223c35297Sanish 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
454323c35297Sanish 
454423c35297Sanish 	range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
454523c35297Sanish 	    PCI_ADDR_IO);
454623c35297Sanish 	range[0].child_low = range[0].parent_low = io_base;
454723c35297Sanish 	range[1].child_high = range[1].parent_high |=
454823c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
454923c35297Sanish 	range[1].child_low = range[1].parent_low = mem_base;
455023c35297Sanish 	range[2].child_high = range[2].parent_high |=
455123c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
455223c35297Sanish 	range[2].child_low = range[2].parent_low = pf_mem_base;
455323c35297Sanish 
455423c35297Sanish 	if (io_size > 0) {
455523c35297Sanish 		range[0].size_low = io_size;
455623c35297Sanish 		(void) pcicfg_update_ranges_prop(new_child, &range[0]);
455723c35297Sanish 	}
455823c35297Sanish 	if (mem_size > 0) {
455923c35297Sanish 		range[1].size_low = mem_size;
456023c35297Sanish 		(void) pcicfg_update_ranges_prop(new_child, &range[1]);
456123c35297Sanish 	}
456223c35297Sanish 	if (pf_mem_size > 0) {
456323c35297Sanish 		range[2].size_low = pf_mem_size;
456423c35297Sanish 		(void) pcicfg_update_ranges_prop(new_child, &range[2]);
456523c35297Sanish 	}
456623c35297Sanish 
456723c35297Sanish 	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
456823c35297Sanish 	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
456923c35297Sanish 	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
457023c35297Sanish 	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
457123c35297Sanish 
457223c35297Sanish 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
457323c35297Sanish 	    "bus-range", bus_range, 2);
457423c35297Sanish 
457523c35297Sanish 	rval = PCICFG_SUCCESS;
457623c35297Sanish 
457723c35297Sanish 	PCICFG_DUMP_BRIDGE_CONFIG(h);
457823c35297Sanish 
457923c35297Sanish cleanup:
458023c35297Sanish 	/* free up resources (for error return case only) */
458123c35297Sanish 	if (rval != PCICFG_SUCCESS) {
458223c35297Sanish 		if (mem_alen)
458323c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
458423c35297Sanish 			    mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
458523c35297Sanish 		if (io_alen)
458623c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(new_child), io_base,
458723c35297Sanish 			    io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
458823c35297Sanish 		if (pf_mem_alen)
458926947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child),
459026947304SEvan Yan 			    pf_mem_base, pf_mem_alen,
459126947304SEvan Yan 			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
459223c35297Sanish 		if (pcibus_alen)
459326947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child),
459426947304SEvan Yan 			    pcibus_base, pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM,
459526947304SEvan Yan 			    NDI_RA_PASS);
459623c35297Sanish 	}
459723c35297Sanish 
459823c35297Sanish 	/* free up any resource maps setup for the bridge node */
459923c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM);
460023c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO);
460123c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM);
460223c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM);
460323c35297Sanish 
460423c35297Sanish 	return (rval);
460523c35297Sanish }
460623c35297Sanish 
460723c35297Sanish static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)460823c35297Sanish pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
460923c35297Sanish {
461023c35297Sanish 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
461123c35297Sanish 	pci_regspec_t *pci_ap;
461223c35297Sanish 	int length;
461323c35297Sanish 	int rcount;
461423c35297Sanish 	int i;
461523c35297Sanish 
461623c35297Sanish 	entry->error = PCICFG_SUCCESS;
461723c35297Sanish 
461823c35297Sanish 	if (dip == entry->dip) {
461923c35297Sanish 		DEBUG0("Don't include parent bridge node\n");
462023c35297Sanish 		return (DDI_WALK_CONTINUE);
462123c35297Sanish 	} else {
462223c35297Sanish 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
462323c35297Sanish 		    DDI_PROP_DONTPASS, "assigned-addresses",
462423c35297Sanish 		    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
462523c35297Sanish 			DEBUG0("Node doesn't have assigned-addresses\n");
462623c35297Sanish 			return (DDI_WALK_CONTINUE);
462723c35297Sanish 		}
462823c35297Sanish 
462923c35297Sanish 		rcount = length / sizeof (pci_regspec_t);
463023c35297Sanish 
463123c35297Sanish 		for (i = 0; i < rcount; i++) {
463223c35297Sanish 
463323c35297Sanish 			switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
463423c35297Sanish 
463523c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
463623c35297Sanish 				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
463723c35297Sanish 					if ((pci_ap[i].pci_phys_low +
463823c35297Sanish 					    pci_ap[i].pci_size_low) >
463923c35297Sanish 					    entry->pf_memory_base) {
464023c35297Sanish 						entry->pf_memory_base =
464123c35297Sanish 						    pci_ap[i].pci_phys_low +
464223c35297Sanish 						    pci_ap[i].pci_size_low;
464323c35297Sanish 					}
464423c35297Sanish 				} else {
464523c35297Sanish 					if ((pci_ap[i].pci_phys_low +
464623c35297Sanish 					    pci_ap[i].pci_size_low) >
464723c35297Sanish 					    entry->memory_base) {
464823c35297Sanish 						entry->memory_base =
464923c35297Sanish 						    pci_ap[i].pci_phys_low +
465023c35297Sanish 						    pci_ap[i].pci_size_low;
465123c35297Sanish 					}
465223c35297Sanish 				}
465323c35297Sanish 				break;
465423c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
465523c35297Sanish 				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
465626947304SEvan Yan 					if ((PCICFG_LADDR(
465726947304SEvan Yan 					    pci_ap[i].pci_phys_low,
465823c35297Sanish 					    pci_ap[i].pci_phys_mid) +
465923c35297Sanish 					    pci_ap[i].pci_size_low) >
466023c35297Sanish 					    entry->pf_memory_base) {
466126947304SEvan Yan 						entry->pf_memory_base =
466226947304SEvan Yan 						    PCICFG_LADDR(
466323c35297Sanish 						    pci_ap[i].pci_phys_low,
466423c35297Sanish 						    pci_ap[i].pci_phys_mid) +
466523c35297Sanish 						    pci_ap[i].pci_size_low;
466623c35297Sanish 					}
466723c35297Sanish 				} else {
466826947304SEvan Yan 					if ((PCICFG_LADDR(
466926947304SEvan Yan 					    pci_ap[i].pci_phys_low,
467023c35297Sanish 					    pci_ap[i].pci_phys_mid) +
467123c35297Sanish 					    pci_ap[i].pci_size_low) >
467223c35297Sanish 					    entry->memory_base) {
467326947304SEvan Yan 						entry->memory_base =
467426947304SEvan Yan 						    PCICFG_LADDR(
467523c35297Sanish 						    pci_ap[i].pci_phys_low,
467623c35297Sanish 						    pci_ap[i].pci_phys_mid) +
467723c35297Sanish 						    pci_ap[i].pci_size_low;
467823c35297Sanish 					}
467923c35297Sanish 				}
468023c35297Sanish 				break;
468123c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
468223c35297Sanish 				if ((pci_ap[i].pci_phys_low +
468323c35297Sanish 				    pci_ap[i].pci_size_low) >
468423c35297Sanish 				    entry->io_base) {
468523c35297Sanish 					entry->io_base =
468623c35297Sanish 					    pci_ap[i].pci_phys_low +
468723c35297Sanish 					    pci_ap[i].pci_size_low;
468823c35297Sanish 				}
468923c35297Sanish 				break;
469023c35297Sanish 			}
469123c35297Sanish 		}
469223c35297Sanish 
469323c35297Sanish 		/*
469423c35297Sanish 		 * free the memory allocated by ddi_getlongprop
469523c35297Sanish 		 */
469623c35297Sanish 		kmem_free(pci_ap, length);
469723c35297Sanish 
469823c35297Sanish 		/*
469923c35297Sanish 		 * continue the walk to the next sibling to sum memory
470023c35297Sanish 		 */
470123c35297Sanish 		return (DDI_WALK_CONTINUE);
470223c35297Sanish 	}
470323c35297Sanish }
470423c35297Sanish 
470523c35297Sanish /*
470623c35297Sanish  * Make "parent" be the parent of the "child" dip
470723c35297Sanish  */
470823c35297Sanish static void
pcicfg_reparent_node(dev_info_t * child,dev_info_t * parent)470923c35297Sanish pcicfg_reparent_node(dev_info_t *child, dev_info_t *parent)
471023c35297Sanish {
471123c35297Sanish 	dev_info_t *opdip;
471223c35297Sanish 
471323c35297Sanish 	ASSERT(i_ddi_node_state(child) <= DS_LINKED);
471423c35297Sanish 	/*
471523c35297Sanish 	 * Unlink node from tree before reparenting
471623c35297Sanish 	 */
471723c35297Sanish 	opdip = ddi_get_parent(child);
47183fe80ca4SDan Cross 	ndi_devi_enter(opdip);
471923c35297Sanish 	(void) i_ndi_unconfig_node(child, DS_PROTO, 0);
47203fe80ca4SDan Cross 	ndi_devi_exit(opdip);
472123c35297Sanish 
472223c35297Sanish 	DEVI(child)->devi_parent = DEVI(parent);
472323c35297Sanish 	DEVI(child)->devi_bus_ctl = DEVI(parent);
472423c35297Sanish 	(void) ndi_devi_bind_driver(child, 0);
472523c35297Sanish }
472623c35297Sanish 
472723c35297Sanish /*
472823c35297Sanish  * Return PCICFG_SUCCESS if device exists at the specified address.
472923c35297Sanish  * Return PCICFG_NODEVICE is no device exists at the specified address.
473023c35297Sanish  */
473123c35297Sanish int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)473223c35297Sanish pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
473323c35297Sanish {
473423c35297Sanish 	caddr_t	cfgaddr;
473523c35297Sanish 	ddi_device_acc_attr_t attr;
473623c35297Sanish 	dev_info_t *anode;
473723c35297Sanish 	int status;
473823c35297Sanish 	int		rlen;
473923c35297Sanish 	pci_regspec_t	*reg;
474023c35297Sanish 	int		ret = DDI_SUCCESS;
474123c35297Sanish 	int16_t		tmp;
474223c35297Sanish 
474323c35297Sanish 	/*
474423c35297Sanish 	 * Get the pci register spec from the node
474523c35297Sanish 	 */
474626947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
474726947304SEvan Yan 	    (caddr_t)&reg, &rlen);
474823c35297Sanish 
474923c35297Sanish 	switch (status) {
475023c35297Sanish 		case DDI_PROP_SUCCESS:
475123c35297Sanish 			break;
475223c35297Sanish 		case DDI_PROP_NO_MEMORY:
475323c35297Sanish 			DEBUG0("reg present, but unable to get memory\n");
475423c35297Sanish 			return (PCICFG_FAILURE);
475523c35297Sanish 		default:
475623c35297Sanish 			DEBUG0("no reg property\n");
475723c35297Sanish 			return (PCICFG_FAILURE);
475823c35297Sanish 	}
475923c35297Sanish 
476023c35297Sanish 	anode = dip;
476123c35297Sanish 	DEBUG2("conf_map: dip=%p, anode=%p\n", dip, anode);
476223c35297Sanish 
476323c35297Sanish 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
476423c35297Sanish 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
476523c35297Sanish 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
476623c35297Sanish 
476726947304SEvan Yan 	if (ddi_regs_map_setup(anode, 0, &cfgaddr, 0, 0, &attr, handle)
476826947304SEvan Yan 	    != DDI_SUCCESS) {
476923c35297Sanish 		DEBUG0("Failed to setup registers\n");
477023c35297Sanish 		kmem_free((caddr_t)reg, rlen);
477123c35297Sanish 		return (PCICFG_FAILURE);
477223c35297Sanish 	}
477323c35297Sanish 
477423c35297Sanish 	/*
477523c35297Sanish 	 * need to use DDI interfaces as the conf space is
477623c35297Sanish 	 * cannot be directly accessed by the host.
477723c35297Sanish 	 */
477823c35297Sanish 	tmp = (int16_t)ddi_get16(*handle, (uint16_t *)cfgaddr);
477923c35297Sanish 	if ((tmp == (int16_t)0xffff) || (tmp == -1)) {
478023c35297Sanish 		DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
478123c35297Sanish 		ret = PCICFG_NODEVICE;
478223c35297Sanish 	} else {
478323c35297Sanish 		if (tmp == 0) {
478423c35297Sanish 			DEBUG0("Device Not Ready yet ?");
478523c35297Sanish 			ret = PCICFG_NODEVICE;
478623c35297Sanish 		} else {
478723c35297Sanish 			DEBUG1("DEVICEFOUND, read %x\n", tmp);
478823c35297Sanish 			ret = PCICFG_SUCCESS;
478923c35297Sanish 		}
479023c35297Sanish 	}
479123c35297Sanish 
479223c35297Sanish 	if (ret == PCICFG_NODEVICE)
479323c35297Sanish 		ddi_regs_map_free(handle);
479423c35297Sanish 	kmem_free((caddr_t)reg, rlen);
479523c35297Sanish 
479623c35297Sanish 	return (ret);
479723c35297Sanish 
479823c35297Sanish }
479923c35297Sanish 
480023c35297Sanish static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)480123c35297Sanish pcicfg_config_teardown(ddi_acc_handle_t *handle)
480223c35297Sanish {
480323c35297Sanish 	(void) ddi_regs_map_free(handle);
480423c35297Sanish }
480523c35297Sanish 
480623c35297Sanish static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)480723c35297Sanish pcicfg_add_config_reg(dev_info_t *dip,
480823c35297Sanish     uint_t bus, uint_t device, uint_t func)
480923c35297Sanish {
481023c35297Sanish 	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
481123c35297Sanish 
481223c35297Sanish 	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
481323c35297Sanish 
481426947304SEvan Yan 	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", reg, 5));
481523c35297Sanish }
481623c35297Sanish 
481726947304SEvan Yan static int
pcicfg_ari_configure(dev_info_t * dip)481826947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip)
481926947304SEvan Yan {
482026947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
482126947304SEvan Yan 		return (DDI_FAILURE);
482226947304SEvan Yan 
482326947304SEvan Yan 	/*
482426947304SEvan Yan 	 * Until we have resource balancing, dynamically configure
482526947304SEvan Yan 	 * ARI functions without firmware assistamce.
482626947304SEvan Yan 	 */
482726947304SEvan Yan 	return (DDI_FAILURE);
482826947304SEvan Yan }
482926947304SEvan Yan 
483026947304SEvan Yan 
483123c35297Sanish #ifdef DEBUG
483223c35297Sanish static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)4833ffb64830SJordan Paige Hendricks debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
4834ffb64830SJordan Paige Hendricks     uintptr_t a5)
483523c35297Sanish {
483623c35297Sanish 	if (pcicfg_debug > 1) {
483723c35297Sanish 		prom_printf("pcicfg: ");
483823c35297Sanish 		prom_printf(fmt, a1, a2, a3, a4, a5);
483923c35297Sanish 	}
484023c35297Sanish }
484123c35297Sanish #endif
484223c35297Sanish 
484323c35297Sanish /*ARGSUSED*/
484423c35297Sanish static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)484523c35297Sanish pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
484623c35297Sanish {
484749fbdd30SErwin T Tsaur 	uint16_t cap_id_loc, slot_id_loc;
484823c35297Sanish 	uint8_t num_slots = 0;
484923c35297Sanish 
485023c35297Sanish 	/* just depend on the pcie_cap for now. */
485149fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
485249fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &slot_id_loc);
485349fbdd30SErwin T Tsaur 	if (cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
485426947304SEvan Yan 		if (pci_config_get8(handle, cap_id_loc + PCI_CAP_ID_REGS_OFF) &
485523c35297Sanish 		    PCIE_PCIECAP_SLOT_IMPL)
485623c35297Sanish 			num_slots = 1;
485723c35297Sanish 	} else /* not a PCIe switch/bridge. Must be a PCI-PCI[-X] bridge */
485849fbdd30SErwin T Tsaur 	if (slot_id_loc != PCI_CAP_NEXT_PTR_NULL) {
485949fbdd30SErwin T Tsaur 		uint8_t esr_reg = pci_config_get8(handle, slot_id_loc + 2);
486023c35297Sanish 		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
486123c35297Sanish 	}
486223c35297Sanish 	/* XXX - need to cover PCI-PCIe bridge with n slots */
486323c35297Sanish 	return (num_slots);
486423c35297Sanish }
486523c35297Sanish 
486623c35297Sanish static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)486723c35297Sanish pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
486823c35297Sanish {
486923c35297Sanish 	int port_type = pcicfg_pcie_port_type(dip, handle);
487023c35297Sanish 
487123c35297Sanish 	DEBUG1("device port_type = %x\n", port_type);
487223c35297Sanish 	/* No PCIe CAP regs, we are not PCIe device_type */
487323c35297Sanish 	if (port_type < 0)
487423c35297Sanish 		return (DDI_FAILURE);
487523c35297Sanish 
487623c35297Sanish 	/* check for all PCIe device_types */
487723c35297Sanish 	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
487823c35297Sanish 	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
487923c35297Sanish 	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
488023c35297Sanish 	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
488123c35297Sanish 		return (DDI_SUCCESS);
488223c35297Sanish 
488323c35297Sanish 	return (DDI_FAILURE);
488423c35297Sanish 
488523c35297Sanish }
488623c35297Sanish 
488723c35297Sanish /*ARGSUSED*/
488823c35297Sanish static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)488923c35297Sanish pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
489023c35297Sanish {
489123c35297Sanish 	int port_type = -1;
489249fbdd30SErwin T Tsaur 	uint16_t cap_loc;
489323c35297Sanish 
489423c35297Sanish 	/* Note: need to look at the port type information here */
489549fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_loc);
489649fbdd30SErwin T Tsaur 	if (cap_loc != PCI_CAP_NEXT_PTR_NULL)
489723c35297Sanish 		port_type = pci_config_get16(handle,
489823c35297Sanish 		    cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
489923c35297Sanish 
490023c35297Sanish 	return (port_type);
490123c35297Sanish }
4902c0da6274SZhi-Jun Robin Fu 
4903c0da6274SZhi-Jun Robin Fu /*
4904c0da6274SZhi-Jun Robin Fu  * Return true if the devinfo node is in a PCI Express hierarchy.
4905c0da6274SZhi-Jun Robin Fu  */
4906c0da6274SZhi-Jun Robin Fu static boolean_t
is_pcie_fabric(dev_info_t * dip)4907c0da6274SZhi-Jun Robin Fu is_pcie_fabric(dev_info_t *dip)
4908c0da6274SZhi-Jun Robin Fu {
4909c0da6274SZhi-Jun Robin Fu 	dev_info_t *root = ddi_root_node();
4910c0da6274SZhi-Jun Robin Fu 	dev_info_t *pdip;
4911c0da6274SZhi-Jun Robin Fu 	boolean_t found = B_FALSE;
4912c0da6274SZhi-Jun Robin Fu 	char *bus;
4913c0da6274SZhi-Jun Robin Fu 
4914c0da6274SZhi-Jun Robin Fu 	/*
4915c0da6274SZhi-Jun Robin Fu 	 * Does this device reside in a pcie fabric ?
4916c0da6274SZhi-Jun Robin Fu 	 */
4917c0da6274SZhi-Jun Robin Fu 	for (pdip = dip; pdip && (pdip != root) && !found;
4918c0da6274SZhi-Jun Robin Fu 	    pdip = ddi_get_parent(pdip)) {
4919c0da6274SZhi-Jun Robin Fu 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
4920c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_DONTPASS, "device_type", &bus) !=
4921c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_SUCCESS)
4922c0da6274SZhi-Jun Robin Fu 			break;
4923c0da6274SZhi-Jun Robin Fu 
4924c0da6274SZhi-Jun Robin Fu 		if (strcmp(bus, "pciex") == 0)
4925c0da6274SZhi-Jun Robin Fu 			found = B_TRUE;
4926c0da6274SZhi-Jun Robin Fu 
4927c0da6274SZhi-Jun Robin Fu 		ddi_prop_free(bus);
4928c0da6274SZhi-Jun Robin Fu 	}
4929c0da6274SZhi-Jun Robin Fu 
4930c0da6274SZhi-Jun Robin Fu 	return (found);
4931c0da6274SZhi-Jun Robin Fu }
4932