xref: /titanic_44/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c (revision 7f59ab1c87b64e613854fb759b15931264bd6307)
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 /*
22*7f59ab1cSAlan Adamson, SD OSSD  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
2323c35297Sanish  */
2423c35297Sanish 
2523c35297Sanish /*
2623c35297Sanish  *     PCI configurator (pcicfg)
2723c35297Sanish  */
2823c35297Sanish 
2923c35297Sanish #include <sys/sysmacros.h>
3023c35297Sanish #include <sys/conf.h>
3123c35297Sanish #include <sys/kmem.h>
3223c35297Sanish #include <sys/debug.h>
3323c35297Sanish #include <sys/modctl.h>
3423c35297Sanish #include <sys/autoconf.h>
3523c35297Sanish #include <sys/hwconf.h>
3623c35297Sanish #include <sys/pcie.h>
3726947304SEvan Yan #include <sys/pcie_impl.h>
3849fbdd30SErwin T Tsaur #include <sys/pci_cap.h>
3923c35297Sanish #include <sys/ddi.h>
4023c35297Sanish #include <sys/sunndi.h>
4123c35297Sanish #include <sys/hotplug/pci/pcicfg.h>
4223c35297Sanish #include <sys/ndi_impldefs.h>
43c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
44c0da6274SZhi-Jun Robin Fu #include <sys/pcie_impl.h>
4523c35297Sanish 
4623c35297Sanish /*
4723c35297Sanish  * ************************************************************************
4823c35297Sanish  * *** Implementation specific local data structures/definitions.	***
4923c35297Sanish  * ************************************************************************
5023c35297Sanish  */
5123c35297Sanish 
5223c35297Sanish static	int	pcicfg_start_devno = 0;	/* for Debug only */
5323c35297Sanish 
5426947304SEvan Yan #define	PCICFG_MAX_ARI_FUNCTION 256
5526947304SEvan Yan 
5623c35297Sanish #define	PCICFG_NODEVICE 42
5723c35297Sanish #define	PCICFG_NOMEMORY 43
5823c35297Sanish #define	PCICFG_NOMULTI	44
595af4ae46Sjveta #define	PCICFG_NORESRC	45
6023c35297Sanish 
6123c35297Sanish #define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & \
6223c35297Sanish 	0xFFFFFFFF00000000ULL)>> 32))
6323c35297Sanish #define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
6423c35297Sanish #define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
6523c35297Sanish 
6623c35297Sanish #define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
6723c35297Sanish #define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
6823c35297Sanish #define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
6923c35297Sanish #define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
7023c35297Sanish 
7123c35297Sanish #define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
7223c35297Sanish #define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
7323c35297Sanish 
7423c35297Sanish #define	PCICFG_MEMGRAN 0x100000
7523c35297Sanish #define	PCICFG_IOGRAN 0x1000
7623c35297Sanish #define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
7723c35297Sanish 
7823c35297Sanish #define	PCICFG_MEM_MULT 4
7923c35297Sanish #define	PCICFG_IO_MULT 4
8023c35297Sanish #define	PCICFG_RANGE_LEN 3 /* Number of range entries */
8123c35297Sanish 
8223c35297Sanish static int pcicfg_slot_busnums = 8;
8323c35297Sanish static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8423c35297Sanish static int pcicfg_slot_pf_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8523c35297Sanish static int pcicfg_slot_iosize = 64 * PCICFG_IOGRAN; /* 64K per slot */
8623c35297Sanish static int pcicfg_sec_reset_delay = 3000000;
8723c35297Sanish static int pcicfg_do_legacy_props = 1;	/* create legacy compatible prop */
8823c35297Sanish 
8923c35297Sanish typedef struct hole hole_t;
9023c35297Sanish 
9123c35297Sanish struct hole {
9223c35297Sanish 	uint64_t	start;
9323c35297Sanish 	uint64_t	len;
9423c35297Sanish 	hole_t		*next;
9523c35297Sanish };
9623c35297Sanish 
9723c35297Sanish typedef struct pcicfg_phdl pcicfg_phdl_t;
9823c35297Sanish 
9923c35297Sanish struct pcicfg_phdl {
10023c35297Sanish 
10123c35297Sanish 	dev_info_t	*dip;		/* Associated with the bridge */
10223c35297Sanish 	dev_info_t	*top_dip;	/* top node of the attach point */
10323c35297Sanish 	pcicfg_phdl_t	*next;
10423c35297Sanish 
10523c35297Sanish 	/* non-prefetchable memory space */
10623c35297Sanish 	uint64_t	memory_base;	/* Memory base for this attach point */
10723c35297Sanish 	uint64_t	memory_last;
10823c35297Sanish 	uint64_t	memory_len;
10923c35297Sanish 
11023c35297Sanish 	/* prefetchable memory space */
11126947304SEvan Yan 	uint64_t	pf_memory_base;	/* PF Memory base for this Connection */
11223c35297Sanish 	uint64_t	pf_memory_last;
11323c35297Sanish 	uint64_t	pf_memory_len;
11423c35297Sanish 
11523c35297Sanish 	/* io space */
11623c35297Sanish 	uint32_t	io_base;	/* I/O base for this attach point */
11723c35297Sanish 	uint32_t	io_last;
11823c35297Sanish 	uint32_t	io_len;
11923c35297Sanish 
12023c35297Sanish 	int		error;
12123c35297Sanish 	uint_t		highest_bus;	/* Highest bus seen on the probe */
12223c35297Sanish 
12323c35297Sanish 	hole_t		mem_hole;	/* Memory hole linked list. */
12423c35297Sanish 	hole_t		pf_mem_hole;	/* PF Memory hole linked list. */
12523c35297Sanish 	hole_t		io_hole;	/* IO hole linked list */
12623c35297Sanish 
12723c35297Sanish 	ndi_ra_request_t mem_req;	/* allocator request for memory */
12823c35297Sanish 	ndi_ra_request_t pf_mem_req;	/* allocator request for PF memory */
12923c35297Sanish 	ndi_ra_request_t io_req;	/* allocator request for I/O */
13023c35297Sanish };
13123c35297Sanish 
13223c35297Sanish struct pcicfg_standard_prop_entry {
13323c35297Sanish     uchar_t *name;
13423c35297Sanish     uint_t  config_offset;
13523c35297Sanish     uint_t  size;
13623c35297Sanish };
13723c35297Sanish 
13823c35297Sanish 
13923c35297Sanish struct pcicfg_name_entry {
14023c35297Sanish     uint32_t class_code;
14123c35297Sanish     char  *name;
14223c35297Sanish };
14323c35297Sanish 
14423c35297Sanish struct pcicfg_find_ctrl {
14523c35297Sanish 	uint_t		device;
14623c35297Sanish 	uint_t		function;
14723c35297Sanish 	dev_info_t	*dip;
14823c35297Sanish };
14923c35297Sanish 
15023c35297Sanish /*
15123c35297Sanish  * List of Indirect Config Map Devices. At least the intent of the
15223c35297Sanish  * design is to look for a device in this list during the configure
15323c35297Sanish  * operation, and if the device is listed here, then it is a nontransparent
15423c35297Sanish  * bridge, hence load the driver and avail the config map services from
15523c35297Sanish  * the driver. Class and Subclass should be as defined in the PCI specs
15623c35297Sanish  * ie. class is 0x6, and subclass is 0x9.
15723c35297Sanish  */
15823c35297Sanish static struct {
15923c35297Sanish 	uint8_t		mem_range_bar_offset;
16023c35297Sanish 	uint8_t		io_range_bar_offset;
16123c35297Sanish 	uint8_t		prefetch_mem_range_bar_offset;
16223c35297Sanish } pcicfg_indirect_map_devs[] = {
16323c35297Sanish 	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
16423c35297Sanish 	0,	0,	0,
16523c35297Sanish };
16623c35297Sanish 
16723c35297Sanish #define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
16823c35297Sanish 	(\
16923c35297Sanish 	((ulong_t)(busnum & 0xff) << 16)    |\
17023c35297Sanish 	((ulong_t)(devnum & 0x1f) << 11)    |\
17123c35297Sanish 	((ulong_t)(funcnum & 0x7) <<  8)    |\
17223c35297Sanish 	((ulong_t)(register & 0x3f)))
17323c35297Sanish 
17423c35297Sanish /*
17523c35297Sanish  * debug macros:
17623c35297Sanish  */
17723c35297Sanish #if	defined(DEBUG)
17823c35297Sanish extern void prom_printf(const char *, ...);
17923c35297Sanish 
18023c35297Sanish /*
18123c35297Sanish  * Following values are defined for this debug flag.
18223c35297Sanish  *
18323c35297Sanish  * 1 = dump configuration header only.
18423c35297Sanish  * 2 = dump generic debug data only (no config header dumped)
18523c35297Sanish  * 3 = dump everything (both 1 and 2)
18623c35297Sanish  */
18723c35297Sanish int pcicfg_debug = 0;
18823c35297Sanish 
18923c35297Sanish static void debug(char *, uintptr_t, uintptr_t,
19023c35297Sanish 	uintptr_t, uintptr_t, uintptr_t);
19123c35297Sanish 
19223c35297Sanish #define	DEBUG0(fmt)\
19323c35297Sanish 	debug(fmt, 0, 0, 0, 0, 0);
19423c35297Sanish #define	DEBUG1(fmt, a1)\
19523c35297Sanish 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
19623c35297Sanish #define	DEBUG2(fmt, a1, a2)\
19723c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
19823c35297Sanish #define	DEBUG3(fmt, a1, a2, a3)\
19923c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20023c35297Sanish 		(uintptr_t)(a3), 0, 0);
20123c35297Sanish #define	DEBUG4(fmt, a1, a2, a3, a4)\
20223c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20323c35297Sanish 		(uintptr_t)(a3), (uintptr_t)(a4), 0);
20423c35297Sanish #define	DEBUG5(fmt, a1, a2, a3, a4, a5)\
20523c35297Sanish 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20623c35297Sanish 		(uintptr_t)(a3), (uintptr_t)(a4), (uintptr_t)(a5));
20723c35297Sanish #else
20823c35297Sanish #define	DEBUG0(fmt)
20923c35297Sanish #define	DEBUG1(fmt, a1)
21023c35297Sanish #define	DEBUG2(fmt, a1, a2)
21123c35297Sanish #define	DEBUG3(fmt, a1, a2, a3)
21223c35297Sanish #define	DEBUG4(fmt, a1, a2, a3, a4)
21323c35297Sanish #define	DEBUG5(fmt, a1, a2, a3, a4, a5)
21423c35297Sanish #endif
21523c35297Sanish 
21623c35297Sanish /*
21723c35297Sanish  * forward declarations for routines defined in this module (called here)
21823c35297Sanish  */
21923c35297Sanish 
22023c35297Sanish static int pcicfg_add_config_reg(dev_info_t *,
22123c35297Sanish     uint_t, uint_t, uint_t);
22223c35297Sanish static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
223c0da6274SZhi-Jun Robin Fu     uint_t *, pcicfg_flags_t, boolean_t);
22423c35297Sanish static int pcicfg_match_dev(dev_info_t *, void *);
22523c35297Sanish static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
22623c35297Sanish static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
22723c35297Sanish static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
22823c35297Sanish static int pcicfg_destroy_phdl(dev_info_t *);
22923c35297Sanish static int pcicfg_sum_resources(dev_info_t *, void *);
23023c35297Sanish static int pcicfg_device_assign(dev_info_t *);
23123c35297Sanish static int pcicfg_bridge_assign(dev_info_t *, void *);
23226947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *);
23326947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
23423c35297Sanish static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23523c35297Sanish static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23623c35297Sanish static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
23723c35297Sanish static void pcicfg_device_on(ddi_acc_handle_t);
23823c35297Sanish static void pcicfg_device_off(ddi_acc_handle_t);
23923c35297Sanish static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
24023c35297Sanish static int pcicfg_free_bridge_resources(dev_info_t *);
24123c35297Sanish static int pcicfg_free_device_resources(dev_info_t *);
242c0da6274SZhi-Jun Robin Fu static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
24323c35297Sanish static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
24423c35297Sanish static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
24523c35297Sanish static void pcicfg_config_teardown(ddi_acc_handle_t *);
24623c35297Sanish static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24723c35297Sanish static void pcicfg_get_pf_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24823c35297Sanish static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
24923c35297Sanish static int pcicfg_update_ranges_prop(dev_info_t *, ppb_ranges_t *);
25023c35297Sanish static int pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
25123c35297Sanish static uint_t pcicfg_ntbridge_child(dev_info_t *);
25223c35297Sanish static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
25323c35297Sanish     uint64_t *, uint_t);
25423c35297Sanish static int pcicfg_is_ntbridge(dev_info_t *);
25523c35297Sanish static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
25623c35297Sanish static int pcicfg_ntbridge_configure_done(dev_info_t *);
25723c35297Sanish static int pcicfg_ntbridge_program_child(dev_info_t *);
25823c35297Sanish static uint_t pcicfg_ntbridge_unconfigure(dev_info_t *);
25923c35297Sanish static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
26023c35297Sanish static void pcicfg_free_hole(hole_t *);
26123c35297Sanish static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
26223c35297Sanish static int pcicfg_device_type(dev_info_t *, ddi_acc_handle_t *);
26323c35297Sanish static void pcicfg_update_phdl(dev_info_t *, uint8_t, uint8_t);
26423c35297Sanish static int pcicfg_get_cap(ddi_acc_handle_t, uint8_t);
26523c35297Sanish static uint8_t pcicfg_get_nslots(dev_info_t *, ddi_acc_handle_t);
26623c35297Sanish static int pcicfg_pcie_dev(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;
55923c35297Sanish 	int circ;
56023c35297Sanish 	uint_t highest_bus;
56126947304SEvan Yan 	int ari_mode = B_FALSE;
56226947304SEvan Yan 	int max_function = PCI_MAX_FUNCTIONS;
56326947304SEvan Yan 	int trans_device;
56426947304SEvan Yan 	dev_info_t *new_device;
565c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
56626947304SEvan Yan 
56726947304SEvan Yan 	if (flags == PCICFG_FLAG_ENABLE_ARI)
56826947304SEvan Yan 		return (pcicfg_ari_configure(devi));
56923c35297Sanish 
57023c35297Sanish 	/*
57123c35297Sanish 	 * Start probing at the device specified in "device" on the
57223c35297Sanish 	 * "bus" specified.
57323c35297Sanish 	 */
57423c35297Sanish 	len = sizeof (pci_bus_range_t);
57523c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, 0, "bus-range",
57623c35297Sanish 	    (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
57723c35297Sanish 		DEBUG0("no bus-range property\n");
57823c35297Sanish 		return (PCICFG_FAILURE);
57923c35297Sanish 	}
58023c35297Sanish 
58123c35297Sanish 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
58223c35297Sanish 
58323c35297Sanish 	attach_point = devi;
58423c35297Sanish 
585c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
586c0da6274SZhi-Jun Robin Fu 
58723c35297Sanish 	ndi_devi_enter(devi, &circ);
58826947304SEvan Yan 	for (func = 0; func < max_function; ) {
58923c35297Sanish 
59026947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
59126947304SEvan Yan 			goto next;
59226947304SEvan Yan 
59326947304SEvan Yan 		if (ari_mode)
59426947304SEvan Yan 			trans_device = func >> 3;
59526947304SEvan Yan 		else
59626947304SEvan Yan 			trans_device = device;
59723c35297Sanish 
59823c35297Sanish 		switch (rv = pcicfg_probe_children(attach_point,
599c0da6274SZhi-Jun Robin Fu 		    bus, trans_device, func & 7, &highest_bus,
600c0da6274SZhi-Jun Robin Fu 		    flags, is_pcie)) {
6015af4ae46Sjveta 			case PCICFG_NORESRC:
60223c35297Sanish 			case PCICFG_FAILURE:
60326947304SEvan Yan 				DEBUG2("configure failed: bus [0x%x] device "
60426947304SEvan Yan 				    "[0x%x]\n", bus, trans_device);
60523c35297Sanish 				goto cleanup;
60623c35297Sanish 			case PCICFG_NODEVICE:
60723c35297Sanish 				DEBUG3("no device : bus "
60823c35297Sanish 				    "[0x%x] slot [0x%x] func [0x%x]\n",
60926947304SEvan Yan 				    bus, trans_device, func &7);
61026947304SEvan Yan 
611*7f59ab1cSAlan Adamson, SD OSSD 				/*
612*7f59ab1cSAlan Adamson, SD OSSD 				 * When walking the list of ARI functions
613*7f59ab1cSAlan Adamson, SD OSSD 				 * we don't expect to see a non-present
614*7f59ab1cSAlan Adamson, SD OSSD 				 * function, so we will stop walking
615*7f59ab1cSAlan Adamson, SD OSSD 				 * the function list.
616*7f59ab1cSAlan Adamson, SD OSSD 				 */
617*7f59ab1cSAlan Adamson, SD OSSD 				if (ari_mode == B_TRUE)
618*7f59ab1cSAlan Adamson, SD OSSD 					break;
619*7f59ab1cSAlan Adamson, SD OSSD 
62026947304SEvan Yan 				if (func)
62126947304SEvan Yan 					goto next;
62226947304SEvan Yan 				break;
62323c35297Sanish 			default:
62423c35297Sanish 				DEBUG3("configure: bus => [%d] "
62523c35297Sanish 				    "slot => [%d] func => [%d]\n",
62626947304SEvan Yan 				    bus, trans_device, func & 7);
62723c35297Sanish 			break;
62823c35297Sanish 		}
62923c35297Sanish 
63023c35297Sanish 		if (rv != PCICFG_SUCCESS)
63123c35297Sanish 			break;
63223c35297Sanish 
63323c35297Sanish 		if ((new_device = pcicfg_devi_find(attach_point,
63426947304SEvan Yan 		    trans_device, func & 7)) == NULL) {
63523c35297Sanish 			DEBUG0("Did'nt find device node just created\n");
63623c35297Sanish 			goto cleanup;
63723c35297Sanish 		}
63823c35297Sanish 
63923c35297Sanish 		/*
64023c35297Sanish 		 * Up until now, we have detected a non transparent bridge
64123c35297Sanish 		 * (ntbridge) as a part of the generic probe code and
64223c35297Sanish 		 * configured only one configuration
64323c35297Sanish 		 * header which is the side facing the host bus.
64423c35297Sanish 		 * Now, configure the other side and create children.
64523c35297Sanish 		 *
64623c35297Sanish 		 * In order to make the process simpler, lets load the device
64723c35297Sanish 		 * driver for the non transparent bridge as this is a
64823c35297Sanish 		 * Solaris bundled driver, and use its configuration map
64923c35297Sanish 		 * services rather than programming it here.
65023c35297Sanish 		 * If the driver is not bundled into Solaris, it must be
65123c35297Sanish 		 * first loaded and configured before performing any
65223c35297Sanish 		 * hotplug operations.
65323c35297Sanish 		 *
65423c35297Sanish 		 * This not only makes the code here simpler but also more
65523c35297Sanish 		 * generic.
65623c35297Sanish 		 *
65723c35297Sanish 		 * So here we go.
65823c35297Sanish 		 */
65923c35297Sanish 
66023c35297Sanish 		/*
66123c35297Sanish 		 * check if this is a bridge in nontransparent mode
66223c35297Sanish 		 */
66323c35297Sanish 		if (pcicfg_is_ntbridge(new_device) != DDI_FAILURE) {
66423c35297Sanish 			DEBUG0("pcicfg: Found nontransparent bridge.\n");
66523c35297Sanish 
66626947304SEvan Yan 			rv = pcicfg_configure_ntbridge(new_device, bus,
66726947304SEvan Yan 			    trans_device);
6685af4ae46Sjveta 			if (rv != PCICFG_SUCCESS)
66923c35297Sanish 				goto cleanup;
67023c35297Sanish 		}
67126947304SEvan Yan 
67226947304SEvan Yan next:
67326947304SEvan Yan 		/*
67426947304SEvan Yan 		 * Determine if ARI Forwarding should be enabled.
67526947304SEvan Yan 		 */
67626947304SEvan Yan 		if (func == 0) {
67726947304SEvan Yan 			if ((pcie_ari_supported(devi)
67826947304SEvan Yan 			    == PCIE_ARI_FORW_SUPPORTED) &&
67926947304SEvan Yan 			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
68026947304SEvan Yan 				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
68126947304SEvan Yan 					(void) ddi_prop_create(DDI_DEV_T_NONE,
68226947304SEvan Yan 					    devi,  DDI_PROP_CANSLEEP,
68326947304SEvan Yan 					    "ari-enabled", NULL, 0);
68426947304SEvan Yan 
68526947304SEvan Yan 					ari_mode = B_TRUE;
68626947304SEvan Yan 					max_function = PCICFG_MAX_ARI_FUNCTION;
68726947304SEvan Yan 				}
68826947304SEvan Yan 			}
68926947304SEvan Yan 		}
69026947304SEvan Yan 		if (ari_mode == B_TRUE) {
69126947304SEvan Yan 			int next_function;
69226947304SEvan Yan 
69326947304SEvan Yan 			DEBUG0("Next Function - ARI Device\n");
69426947304SEvan Yan 			if (pcie_ari_get_next_function(new_device,
69526947304SEvan Yan 			    &next_function) != DDI_SUCCESS)
69626947304SEvan Yan 				goto cleanup;
69726947304SEvan Yan 
69826947304SEvan Yan 			/*
69926947304SEvan Yan 			 * Check if there are more fucntions to probe.
70026947304SEvan Yan 			 */
70126947304SEvan Yan 			if (next_function == 0) {
70226947304SEvan Yan 				DEBUG0("Next Function - "
70326947304SEvan Yan 				    "No more ARI Functions\n");
70426947304SEvan Yan 				break;
70526947304SEvan Yan 			}
70626947304SEvan Yan 			func = next_function;
70726947304SEvan Yan 		} else {
70826947304SEvan Yan 			func++;
70926947304SEvan Yan 		}
71026947304SEvan Yan 		DEBUG1("Next Function - %x\n", func);
71123c35297Sanish 	}
71223c35297Sanish 
71323c35297Sanish 	ndi_devi_exit(devi, circ);
71423c35297Sanish 
71523c35297Sanish 	if (func == 0)
71623c35297Sanish 		return (PCICFG_FAILURE);	/* probe failed */
71723c35297Sanish 	else
71823c35297Sanish 		return (PCICFG_SUCCESS);
71923c35297Sanish 
72023c35297Sanish cleanup:
72123c35297Sanish 	/*
72223c35297Sanish 	 * Clean up a partially created "probe state" tree.
72323c35297Sanish 	 * There are no resources allocated to the in the
72423c35297Sanish 	 * probe state.
72523c35297Sanish 	 */
72623c35297Sanish 
72723c35297Sanish 	for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
72826947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
72926947304SEvan Yan 			continue;
73026947304SEvan Yan 
73126947304SEvan Yan 		if ((new_device = pcicfg_devi_find(devi, device, func))
73226947304SEvan Yan 		    == NULL) {
73323c35297Sanish 			continue;
73423c35297Sanish 		}
73523c35297Sanish 
73623c35297Sanish 		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
73723c35297Sanish 		    device, func);
73823c35297Sanish 		/*
73923c35297Sanish 		 * If this was a bridge device it will have a
74023c35297Sanish 		 * probe handle - if not, no harm in calling this.
74123c35297Sanish 		 */
74223c35297Sanish 		(void) pcicfg_destroy_phdl(new_device);
743c0da6274SZhi-Jun Robin Fu 		if (is_pcie) {
744c0da6274SZhi-Jun Robin Fu 			/*
745c0da6274SZhi-Jun Robin Fu 			 * free pcie_bus_t for the sub-tree
746c0da6274SZhi-Jun Robin Fu 			 */
747c0da6274SZhi-Jun Robin Fu 			if (ddi_get_child(new_device) != NULL)
748c0da6274SZhi-Jun Robin Fu 				pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
749c0da6274SZhi-Jun Robin Fu 
750c0da6274SZhi-Jun Robin Fu 			pcie_fini_bus(new_device, PCIE_BUS_ALL);
751c0da6274SZhi-Jun Robin Fu 		}
75223c35297Sanish 		/*
75323c35297Sanish 		 * This will free up the node
75423c35297Sanish 		 */
75523c35297Sanish 		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
75623c35297Sanish 	}
75723c35297Sanish 	ndi_devi_exit(devi, circ);
75823c35297Sanish 
7595af4ae46Sjveta 	/*
7605af4ae46Sjveta 	 * Use private return codes to help identify issues without debugging
7615af4ae46Sjveta 	 * enabled.  Resource limitations and mis-configurations are
7625af4ae46Sjveta 	 * probably the most likely caue of configuration failures on x86.
7635af4ae46Sjveta 	 * Convert return code back to values expected by the external
7645af4ae46Sjveta 	 * consumer before returning so we will warn only once on the first
7655af4ae46Sjveta 	 * encountered failure.
7665af4ae46Sjveta 	 */
7675af4ae46Sjveta 	if (rv == PCICFG_NORESRC) {
7685af4ae46Sjveta 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7695af4ae46Sjveta 
7705af4ae46Sjveta 		(void) ddi_pathname(devi, path);
7715af4ae46Sjveta 		cmn_err(CE_CONT, "?Not enough PCI resources to "
7725af4ae46Sjveta 		    "configure: %s\n", path);
7735af4ae46Sjveta 
7745af4ae46Sjveta 		kmem_free(path, MAXPATHLEN);
7755af4ae46Sjveta 		rv = PCICFG_FAILURE;
7765af4ae46Sjveta 	}
7775af4ae46Sjveta 
7785af4ae46Sjveta 	return (rv);
77923c35297Sanish }
78023c35297Sanish 
78123c35297Sanish /*
78223c35297Sanish  * configure the child nodes of ntbridge. new_device points to ntbridge itself
78323c35297Sanish  */
78423c35297Sanish /*ARGSUSED*/
78523c35297Sanish static int
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)78623c35297Sanish pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
78723c35297Sanish {
78823c35297Sanish 	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
78923c35297Sanish 	int			devno;
79023c35297Sanish 	dev_info_t		*new_ntbridgechild;
79123c35297Sanish 	ddi_acc_handle_t	config_handle;
79223c35297Sanish 	uint16_t		vid;
79323c35297Sanish 	uint64_t		next_bus;
79423c35297Sanish 	uint64_t		blen;
79523c35297Sanish 	ndi_ra_request_t	req;
79623c35297Sanish 	uint8_t			pcie_device_type = 0;
79723c35297Sanish 
79823c35297Sanish 	/*
79923c35297Sanish 	 * If we need to do indirect config, lets create a property here
80023c35297Sanish 	 * to let the child conf map routine know that it has to
80123c35297Sanish 	 * go through the DDI calls, and not assume the devices are
80223c35297Sanish 	 * mapped directly under the host.
80323c35297Sanish 	 */
80423c35297Sanish 	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
80526947304SEvan Yan 	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) != DDI_SUCCESS) {
80623c35297Sanish 		DEBUG0("Cannot create indirect conf map property.\n");
80723c35297Sanish 		return ((int)PCICFG_FAILURE);
80823c35297Sanish 	}
80923c35297Sanish 
81023c35297Sanish 	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
81123c35297Sanish 		return (PCICFG_FAILURE);
81223c35297Sanish 	/* check if we are PCIe device */
81323c35297Sanish 	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) {
81423c35297Sanish 		DEBUG0("PCIe device detected\n");
81523c35297Sanish 		pcie_device_type = 1;
81623c35297Sanish 	}
81723c35297Sanish 	pci_config_teardown(&config_handle);
81823c35297Sanish 	/* create Bus node properties for ntbridge. */
81923c35297Sanish 	if (pcicfg_set_busnode_props(new_device, pcie_device_type)
82023c35297Sanish 	    != PCICFG_SUCCESS) {
82123c35297Sanish 		DEBUG0("Failed to set busnode props\n");
82223c35297Sanish 		return (rc);
82323c35297Sanish 	}
82423c35297Sanish 
82523c35297Sanish 	/* For now: Lets only support one layer of child */
82623c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
82723c35297Sanish 	req.ra_len = 1;
82826947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(new_device), &req, &next_bus, &blen,
82926947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
83023c35297Sanish 		DEBUG0("ntbridge: Failed to get a bus number\n");
8315af4ae46Sjveta 		return (PCICFG_NORESRC);
83223c35297Sanish 	}
83323c35297Sanish 
83423c35297Sanish 	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
83523c35297Sanish 
83623c35297Sanish 	/*
83723c35297Sanish 	 * Following will change, as we detect more bridges
83823c35297Sanish 	 * on the way.
83923c35297Sanish 	 */
84023c35297Sanish 	bus_range[0] = (int)next_bus;
84123c35297Sanish 	bus_range[1] = (int)next_bus;
84223c35297Sanish 
84326947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, "bus-range",
84426947304SEvan Yan 	    bus_range, 2) != DDI_SUCCESS) {
84523c35297Sanish 		DEBUG0("Cannot set ntbridge bus-range property");
84623c35297Sanish 		return (rc);
84723c35297Sanish 	}
84823c35297Sanish 
84923c35297Sanish 	/*
85023c35297Sanish 	 * The other interface (away from the host) will be
85123c35297Sanish 	 * initialized by the nexus driver when it loads.
85223c35297Sanish 	 * We just have to set the registers and the nexus driver
85323c35297Sanish 	 * figures out the rest.
85423c35297Sanish 	 */
85523c35297Sanish 
85623c35297Sanish 	/*
85723c35297Sanish 	 * finally, lets load and attach the driver
85823c35297Sanish 	 * before configuring children of ntbridge.
85923c35297Sanish 	 */
86023c35297Sanish 	rc = ndi_devi_online(new_device, NDI_ONLINE_ATTACH|NDI_CONFIG);
86123c35297Sanish 	if (rc != NDI_SUCCESS) {
86223c35297Sanish 		cmn_err(CE_WARN,
86323c35297Sanish 		"pcicfg: Fail:cant load nontransparent bridgd driver..\n");
86423c35297Sanish 		rc = PCICFG_FAILURE;
86523c35297Sanish 		return (rc);
86623c35297Sanish 	}
86723c35297Sanish 	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
86823c35297Sanish 
8695af4ae46Sjveta 	/* Now set aside pci resource allocation requests for our children */
87026947304SEvan Yan 	if (pcicfg_ntbridge_allocate_resources(new_device) != PCICFG_SUCCESS) {
87123c35297Sanish 		max_devs = 0;
87223c35297Sanish 		rc = PCICFG_FAILURE;
87323c35297Sanish 	} else
87423c35297Sanish 		max_devs = PCI_MAX_DEVICES;
87523c35297Sanish 
87623c35297Sanish 	/* Probe devices on 2nd bus */
8775af4ae46Sjveta 	rc = PCICFG_SUCCESS;
87823c35297Sanish 	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
87923c35297Sanish 
88023c35297Sanish 		ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
88123c35297Sanish 		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
88223c35297Sanish 
88323c35297Sanish 		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
88423c35297Sanish 		    != DDI_PROP_SUCCESS) {
88523c35297Sanish 			cmn_err(CE_WARN,
88623c35297Sanish 			    "Failed to add conf reg for ntbridge child.\n");
88723c35297Sanish 			(void) ndi_devi_free(new_ntbridgechild);
88823c35297Sanish 			rc = PCICFG_FAILURE;
88923c35297Sanish 			break;
89023c35297Sanish 		}
89123c35297Sanish 
89223c35297Sanish 		if (pci_config_setup(new_ntbridgechild, &config_handle)
89323c35297Sanish 		    != DDI_SUCCESS) {
89423c35297Sanish 			cmn_err(CE_WARN,
89523c35297Sanish 			    "Cannot map ntbridge child %x\n", devno);
89623c35297Sanish 			(void) ndi_devi_free(new_ntbridgechild);
89723c35297Sanish 			rc = PCICFG_FAILURE;
89823c35297Sanish 			break;
89923c35297Sanish 		}
90023c35297Sanish 
90123c35297Sanish 		/*
90223c35297Sanish 		 * See if there is any PCI HW at this location
90323c35297Sanish 		 * by reading the Vendor ID.  If it returns with 0xffff
90423c35297Sanish 		 * then there is no hardware at this location.
90523c35297Sanish 		 */
90623c35297Sanish 		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
90723c35297Sanish 
90823c35297Sanish 		pci_config_teardown(&config_handle);
90923c35297Sanish 		(void) ndi_devi_free(new_ntbridgechild);
91023c35297Sanish 		if (vid	== 0xffff)
91123c35297Sanish 			continue;
91223c35297Sanish 
91323c35297Sanish 		/* Lets fake attachments points for each child, */
91426947304SEvan Yan 		rc = pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0);
9155af4ae46Sjveta 		if (rc != PCICFG_SUCCESS) {
91623c35297Sanish 			int old_dev = pcicfg_start_devno;
91723c35297Sanish 
91823c35297Sanish 			cmn_err(CE_WARN,
91923c35297Sanish 			    "Error configuring ntbridge child dev=%d\n", devno);
92023c35297Sanish 
92123c35297Sanish 			while (old_dev != devno) {
92223c35297Sanish 				if (pcicfg_ntbridge_unconfigure_child(
92323c35297Sanish 				    new_device, old_dev) == PCICFG_FAILURE)
92426947304SEvan Yan 					cmn_err(CE_WARN, "Unconfig Error "
92526947304SEvan Yan 					    "ntbridge child dev=%d\n", old_dev);
92623c35297Sanish 				old_dev++;
92723c35297Sanish 			}
92823c35297Sanish 			break;
92923c35297Sanish 		}
93023c35297Sanish 	} /* devno loop */
93123c35297Sanish 	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
93223c35297Sanish 
9335af4ae46Sjveta 	if (rc == PCICFG_SUCCESS)
93423c35297Sanish 		rc = pcicfg_ntbridge_configure_done(new_device);
93523c35297Sanish 	else {
93623c35297Sanish 		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
93723c35297Sanish 		uint_t			*bus;
93823c35297Sanish 		int			k;
93923c35297Sanish 
94023c35297Sanish 		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
94126947304SEvan Yan 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, &k)
94226947304SEvan Yan 		    != DDI_PROP_SUCCESS) {
94323c35297Sanish 			DEBUG0("Failed to read bus-range property\n");
94423c35297Sanish 			rc = PCICFG_FAILURE;
94523c35297Sanish 			return (rc);
94623c35297Sanish 		}
94723c35297Sanish 
94823c35297Sanish 		DEBUG2("Need to free bus [%d] range [%d]\n",
94923c35297Sanish 		    bus[0], bus[1] - bus[0] + 1);
95023c35297Sanish 
95126947304SEvan Yan 		if (ndi_ra_free(ddi_get_parent(new_device), (uint64_t)bus[0],
95226947304SEvan Yan 		    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
95326947304SEvan Yan 		    NDI_RA_PASS) != NDI_SUCCESS) {
95423c35297Sanish 			DEBUG0("Failed to free a bus number\n");
95523c35297Sanish 			rc = PCICFG_FAILURE;
9561fb5b786Sprasad 			kmem_free(bus, k);
95723c35297Sanish 			return (rc);
95823c35297Sanish 		}
95923c35297Sanish 
96023c35297Sanish 		/*
96123c35297Sanish 		 * Since no memory allocations are done for non transparent
96223c35297Sanish 		 * bridges (but instead we just set the handle with the
96323c35297Sanish 		 * already allocated memory, we just need to reset the
96423c35297Sanish 		 * following values before calling the destroy_phdl()
96523c35297Sanish 		 * function next, otherwise the it will try to free
96623c35297Sanish 		 * memory allocated as in case of a transparent bridge.
96723c35297Sanish 		 */
96823c35297Sanish 		entry->memory_len = 0;
96923c35297Sanish 		entry->pf_memory_len = 0;
97023c35297Sanish 		entry->io_len = 0;
9711fb5b786Sprasad 		kmem_free(bus, k);
97223c35297Sanish 		/* the following will free hole data. */
97323c35297Sanish 		(void) pcicfg_destroy_phdl(new_device);
97423c35297Sanish 	}
97523c35297Sanish 
97623c35297Sanish 	/*
97723c35297Sanish 	 * Unload driver just in case child configure failed!
97823c35297Sanish 	 */
97923c35297Sanish 	rc1 = ndi_devi_offline(new_device, 0);
98023c35297Sanish 	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
98123c35297Sanish 	if (rc1 != NDI_SUCCESS) {
98223c35297Sanish 		cmn_err(CE_WARN,
98323c35297Sanish 		"pcicfg: cant unload ntbridge driver..children.\n");
98423c35297Sanish 		rc = PCICFG_FAILURE;
98523c35297Sanish 	}
98623c35297Sanish 
98723c35297Sanish 	return (rc);
98823c35297Sanish }
98923c35297Sanish 
99023c35297Sanish static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)99123c35297Sanish pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
99223c35297Sanish {
99323c35297Sanish 	pcicfg_phdl_t		*phdl;
99423c35297Sanish 	ndi_ra_request_t	*mem_request;
99523c35297Sanish 	ndi_ra_request_t	*pf_mem_request;
99623c35297Sanish 	ndi_ra_request_t	*io_request;
99723c35297Sanish 	uint64_t		boundbase, boundlen;
99823c35297Sanish 
99923c35297Sanish 	phdl = pcicfg_find_phdl(dip);
100023c35297Sanish 	ASSERT(phdl);
100123c35297Sanish 
100223c35297Sanish 	mem_request = &phdl->mem_req;
100323c35297Sanish 	pf_mem_request = &phdl->pf_mem_req;
100423c35297Sanish 	io_request  = &phdl->io_req;
100523c35297Sanish 
100623c35297Sanish 	phdl->error = PCICFG_SUCCESS;
100723c35297Sanish 
100823c35297Sanish 	/* Set Memory space handle for ntbridge */
100923c35297Sanish 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
101023c35297Sanish 	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
101123c35297Sanish 		cmn_err(CE_WARN,
101223c35297Sanish 		    "ntbridge: Mem resource information failure\n");
101323c35297Sanish 		phdl->memory_len  = 0;
101423c35297Sanish 		return (PCICFG_FAILURE);
101523c35297Sanish 	}
101623c35297Sanish 	mem_request->ra_boundbase = boundbase;
101723c35297Sanish 	mem_request->ra_boundlen = boundbase + boundlen;
101823c35297Sanish 	mem_request->ra_len = boundlen;
101923c35297Sanish 	mem_request->ra_align_mask =
102023c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
102123c35297Sanish 	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
102223c35297Sanish 
102323c35297Sanish 	/*
102423c35297Sanish 	 * mem_request->ra_len =
102523c35297Sanish 	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
102623c35297Sanish 	 */
102723c35297Sanish 
102823c35297Sanish 	phdl->memory_base = phdl->memory_last = boundbase;
102923c35297Sanish 	phdl->memory_len  = boundlen;
103023c35297Sanish 	phdl->mem_hole.start = phdl->memory_base;
103123c35297Sanish 	phdl->mem_hole.len = mem_request->ra_len;
103223c35297Sanish 	phdl->mem_hole.next = (hole_t *)NULL;
103323c35297Sanish 
103426947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
103523c35297Sanish 	    boundlen, mem_request->ra_len);
103623c35297Sanish 
103723c35297Sanish 	/* Set IO space handle for ntbridge */
103823c35297Sanish 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
103923c35297Sanish 	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
104023c35297Sanish 		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
104123c35297Sanish 		phdl->io_len  = 0;
104223c35297Sanish 		return (PCICFG_FAILURE);
104323c35297Sanish 	}
104423c35297Sanish 	io_request->ra_len = boundlen;
104523c35297Sanish 	io_request->ra_align_mask =
104623c35297Sanish 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
104723c35297Sanish 	io_request->ra_boundbase = boundbase;
104823c35297Sanish 	io_request->ra_boundlen = boundbase + boundlen;
104923c35297Sanish 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
105023c35297Sanish 
105123c35297Sanish 	/*
105223c35297Sanish 	 * io_request->ra_len =
105323c35297Sanish 	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
105423c35297Sanish 	 */
105523c35297Sanish 
105623c35297Sanish 	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
105723c35297Sanish 	phdl->io_len  = (uint32_t)boundlen;
105823c35297Sanish 	phdl->io_hole.start = phdl->io_base;
105923c35297Sanish 	phdl->io_hole.len = io_request->ra_len;
106023c35297Sanish 	phdl->io_hole.next = (hole_t *)NULL;
106123c35297Sanish 
106226947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
106323c35297Sanish 	    boundlen, io_request->ra_len);
106423c35297Sanish 
106523c35297Sanish 	/* Set Prefetchable Memory space handle for ntbridge */
106623c35297Sanish 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
106723c35297Sanish 	    PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
106823c35297Sanish 		cmn_err(CE_WARN,
106923c35297Sanish 		    "ntbridge: PF Mem resource information failure\n");
107023c35297Sanish 		phdl->pf_memory_len  = 0;
107123c35297Sanish 		return (PCICFG_FAILURE);
107223c35297Sanish 	}
107323c35297Sanish 	pf_mem_request->ra_boundbase = boundbase;
107423c35297Sanish 	pf_mem_request->ra_boundlen = boundbase + boundlen;
107523c35297Sanish 	pf_mem_request->ra_len = boundlen;
107623c35297Sanish 	pf_mem_request->ra_align_mask =
107723c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
107823c35297Sanish 	pf_mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
107923c35297Sanish 
108023c35297Sanish 	/*
108123c35297Sanish 	 * pf_mem_request->ra_len =
108223c35297Sanish 	 * PCICFG_ROUND_UP(pf_mem_request->ra_len, PCICFG_MEMGRAN);
108323c35297Sanish 	 */
108423c35297Sanish 
108523c35297Sanish 	phdl->pf_memory_base = phdl->pf_memory_last = boundbase;
108623c35297Sanish 	phdl->pf_memory_len  = boundlen;
108723c35297Sanish 	phdl->pf_mem_hole.start = phdl->pf_memory_base;
108823c35297Sanish 	phdl->pf_mem_hole.len = pf_mem_request->ra_len;
108923c35297Sanish 	phdl->pf_mem_hole.next = (hole_t *)NULL;
109023c35297Sanish 
109126947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of PF "
109226947304SEvan Yan 	    "memory\n", boundlen, pf_mem_request->ra_len);
109323c35297Sanish 
109423c35297Sanish 	DEBUG2("MEMORY BASE = [0x%lx] length [0x%lx]\n",
109523c35297Sanish 	    phdl->memory_base, phdl->memory_len);
109623c35297Sanish 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
109723c35297Sanish 	    phdl->io_base, phdl->io_len);
109823c35297Sanish 	DEBUG2("PF MEMORY BASE = [0x%lx] length [0x%lx]\n",
109923c35297Sanish 	    phdl->pf_memory_base, phdl->pf_memory_len);
110023c35297Sanish 
110123c35297Sanish 	return (PCICFG_SUCCESS);
110223c35297Sanish }
110323c35297Sanish 
110423c35297Sanish static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)110523c35297Sanish pcicfg_ntbridge_configure_done(dev_info_t *dip)
110623c35297Sanish {
110723c35297Sanish 	ppb_ranges_t range[PCICFG_RANGE_LEN];
110823c35297Sanish 	pcicfg_phdl_t		*entry;
110923c35297Sanish 	uint_t			len;
111023c35297Sanish 	pci_bus_range_t		bus_range;
111123c35297Sanish 	int			new_bus_range[2];
111223c35297Sanish 
111323c35297Sanish 	DEBUG1("Configuring children for %p\n", dip);
111423c35297Sanish 
111523c35297Sanish 	entry = pcicfg_find_phdl(dip);
111623c35297Sanish 	ASSERT(entry);
111723c35297Sanish 
111826947304SEvan Yan 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
111923c35297Sanish 	range[1].child_high = range[1].parent_high |=
112023c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
112123c35297Sanish 	range[1].child_low = range[1].parent_low = (uint32_t)entry->memory_base;
112223c35297Sanish 
112323c35297Sanish 	range[0].child_high = range[0].parent_high |=
112423c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_IO);
112523c35297Sanish 	range[0].child_low = range[0].parent_low = (uint32_t)entry->io_base;
112623c35297Sanish 
112723c35297Sanish 	range[2].child_high = range[2].parent_high |=
112823c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
112923c35297Sanish 	range[2].child_low = range[2].parent_low =
113023c35297Sanish 	    (uint32_t)entry->pf_memory_base;
113123c35297Sanish 
113223c35297Sanish 	len = sizeof (pci_bus_range_t);
113323c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
113423c35297Sanish 	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
113523c35297Sanish 		DEBUG0("no bus-range property\n");
113623c35297Sanish 		return (PCICFG_FAILURE);
113723c35297Sanish 	}
113823c35297Sanish 
113923c35297Sanish 	new_bus_range[0] = bus_range.lo;	/* primary bus number */
114023c35297Sanish 	if (entry->highest_bus) {	/* secondary bus number */
114123c35297Sanish 		if (entry->highest_bus < bus_range.lo) {
114223c35297Sanish 			cmn_err(CE_WARN,
114323c35297Sanish 			    "ntbridge bus range invalid !(%d,%d)\n",
114423c35297Sanish 			    bus_range.lo, entry->highest_bus);
114523c35297Sanish 			new_bus_range[1] = bus_range.lo + entry->highest_bus;
114623c35297Sanish 		}
114723c35297Sanish 		else
114823c35297Sanish 			new_bus_range[1] = entry->highest_bus;
114923c35297Sanish 	}
115023c35297Sanish 	else
115123c35297Sanish 		new_bus_range[1] = bus_range.hi;
115223c35297Sanish 
115326947304SEvan Yan 	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", new_bus_range[0],
115426947304SEvan Yan 	    new_bus_range[1]);
115523c35297Sanish 
115626947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "bus-range",
115726947304SEvan Yan 	    new_bus_range, 2) != DDI_SUCCESS) {
115823c35297Sanish 		DEBUG0("Failed to set bus-range property");
115923c35297Sanish 		entry->error = PCICFG_FAILURE;
116023c35297Sanish 		return (PCICFG_FAILURE);
116123c35297Sanish 	}
116223c35297Sanish 
116323c35297Sanish #ifdef DEBUG
116423c35297Sanish 	{
116523c35297Sanish 		uint64_t	unused;
116623c35297Sanish 		unused = pcicfg_unused_space(&entry->io_hole, &len);
116723c35297Sanish 		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
116823c35297Sanish 		    unused, len);
116923c35297Sanish 	}
117023c35297Sanish #endif
117123c35297Sanish 
117223c35297Sanish 	range[0].size_low = entry->io_len;
117323c35297Sanish 	if (pcicfg_update_ranges_prop(dip, &range[0])) {
117423c35297Sanish 		DEBUG0("Failed to update ranges (i/o)\n");
117523c35297Sanish 		entry->error = PCICFG_FAILURE;
117623c35297Sanish 		return (PCICFG_FAILURE);
117723c35297Sanish 	}
117823c35297Sanish 
117923c35297Sanish #ifdef DEBUG
118023c35297Sanish 	{
118123c35297Sanish 		uint64_t	unused;
118223c35297Sanish 		unused = pcicfg_unused_space(&entry->mem_hole, &len);
118323c35297Sanish 		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
118423c35297Sanish 		    unused, len);
118523c35297Sanish 	}
118623c35297Sanish #endif
118723c35297Sanish 
118823c35297Sanish 	range[1].size_low = entry->memory_len;
118923c35297Sanish 	if (pcicfg_update_ranges_prop(dip, &range[1])) {
119023c35297Sanish 		DEBUG0("Failed to update ranges (memory)\n");
119123c35297Sanish 		entry->error = PCICFG_FAILURE;
119223c35297Sanish 		return (PCICFG_FAILURE);
119323c35297Sanish 	}
119423c35297Sanish 
119523c35297Sanish #ifdef DEBUG
119623c35297Sanish 	{
119723c35297Sanish 		uint64_t	unused;
119823c35297Sanish 		unused = pcicfg_unused_space(&entry->pf_mem_hole, &len);
119923c35297Sanish 		DEBUG2("ntbridge: Unused PF Mem space %llx bytes over"
120023c35297Sanish 		    " %d holes\n", unused, len);
120123c35297Sanish 	}
120223c35297Sanish #endif
120323c35297Sanish 
120423c35297Sanish 	range[2].size_low = entry->pf_memory_len;
120523c35297Sanish 	if (pcicfg_update_ranges_prop(dip, &range[2])) {
120623c35297Sanish 		DEBUG0("Failed to update ranges (PF memory)\n");
120723c35297Sanish 		entry->error = PCICFG_FAILURE;
120823c35297Sanish 		return (PCICFG_FAILURE);
120923c35297Sanish 	}
121023c35297Sanish 
121123c35297Sanish 	return (PCICFG_SUCCESS);
121223c35297Sanish }
121323c35297Sanish 
121423c35297Sanish static int
pcicfg_ntbridge_program_child(dev_info_t * dip)121523c35297Sanish pcicfg_ntbridge_program_child(dev_info_t *dip)
121623c35297Sanish {
121723c35297Sanish 	pcicfg_phdl_t	*entry;
121823c35297Sanish 	int		rc = PCICFG_SUCCESS;
121923c35297Sanish 	dev_info_t	*anode = dip;
122023c35297Sanish 
122126947304SEvan Yan 	/* Find the Hotplug Connection (CN) node */
122226947304SEvan Yan 	while ((anode != NULL) &&
122326947304SEvan Yan 	    (strcmp(ddi_binding_name(anode), "hp_attachment") != 0)) {
122423c35297Sanish 		anode = ddi_get_parent(anode);
122523c35297Sanish 	}
122623c35297Sanish 
122723c35297Sanish 	if (anode == NULL) {
122823c35297Sanish 		DEBUG0("ntbridge child tree not in PROBE state\n");
122923c35297Sanish 		return (PCICFG_FAILURE);
123023c35297Sanish 	}
123123c35297Sanish 	entry = pcicfg_find_phdl(ddi_get_parent(anode));
123223c35297Sanish 	ASSERT(entry);
123323c35297Sanish 
123423c35297Sanish 	if (pcicfg_bridge_assign(dip, entry) == DDI_WALK_TERMINATE) {
123523c35297Sanish 		cmn_err(CE_WARN,
123623c35297Sanish 		    "ntbridge: Error assigning range for child %s\n",
123723c35297Sanish 		    ddi_get_name(dip));
123823c35297Sanish 		rc = PCICFG_FAILURE;
123923c35297Sanish 	}
124023c35297Sanish 	return (rc);
124123c35297Sanish }
124223c35297Sanish 
124323c35297Sanish static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)124423c35297Sanish pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
124523c35297Sanish {
124623c35297Sanish 
124723c35297Sanish 	dev_info_t	*new_ntbridgechild;
124823c35297Sanish 	int 		len, bus;
124923c35297Sanish 	uint16_t	vid;
125023c35297Sanish 	ddi_acc_handle_t	config_handle;
125123c35297Sanish 	pci_bus_range_t pci_bus_range;
125223c35297Sanish 
125323c35297Sanish 	len = sizeof (pci_bus_range_t);
125423c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
125523c35297Sanish 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
125623c35297Sanish 		DEBUG0("no bus-range property\n");
125723c35297Sanish 		return (PCICFG_FAILURE);
125823c35297Sanish 	}
125923c35297Sanish 
126023c35297Sanish 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
126123c35297Sanish 
126223c35297Sanish 	ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
126323c35297Sanish 	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
126423c35297Sanish 
126523c35297Sanish 	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
126623c35297Sanish 	    != DDI_PROP_SUCCESS) {
126726947304SEvan Yan 		cmn_err(CE_WARN, "Unconfigure: Failed to add conf reg prop for "
126826947304SEvan Yan 		    "ntbridge child.\n");
126923c35297Sanish 		(void) ndi_devi_free(new_ntbridgechild);
127023c35297Sanish 		return (PCICFG_FAILURE);
127123c35297Sanish 	}
127223c35297Sanish 
127323c35297Sanish 	if (pci_config_setup(new_ntbridgechild, &config_handle)
127423c35297Sanish 	    != DDI_SUCCESS) {
127526947304SEvan Yan 		cmn_err(CE_WARN, "pcicfg: Cannot map ntbridge child %x\n",
127626947304SEvan Yan 		    devno);
127723c35297Sanish 		(void) ndi_devi_free(new_ntbridgechild);
127823c35297Sanish 		return (PCICFG_FAILURE);
127923c35297Sanish 	}
128023c35297Sanish 
128123c35297Sanish 	/*
128223c35297Sanish 	 * See if there is any PCI HW at this location
128323c35297Sanish 	 * by reading the Vendor ID.  If it returns with 0xffff
128423c35297Sanish 	 * then there is no hardware at this location.
128523c35297Sanish 	 */
128623c35297Sanish 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
128723c35297Sanish 
128823c35297Sanish 	pci_config_teardown(&config_handle);
128923c35297Sanish 	(void) ndi_devi_free(new_ntbridgechild);
129023c35297Sanish 	if (vid	== 0xffff)
129123c35297Sanish 		return (PCICFG_NODEVICE);
129223c35297Sanish 
129326947304SEvan Yan 	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
129423c35297Sanish }
129523c35297Sanish 
129623c35297Sanish static uint_t
pcicfg_ntbridge_unconfigure(dev_info_t * dip)129723c35297Sanish pcicfg_ntbridge_unconfigure(dev_info_t *dip)
129823c35297Sanish {
129923c35297Sanish 	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
130023c35297Sanish 	uint_t			*bus;
130123c35297Sanish 	int			k, rc = DDI_FAILURE;
130223c35297Sanish 
130326947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range",
130426947304SEvan Yan 	    (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
130523c35297Sanish 		DEBUG0("ntbridge: Failed to read bus-range property\n");
130623c35297Sanish 		return (rc);
130723c35297Sanish 	}
130823c35297Sanish 
130923c35297Sanish 	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
131023c35297Sanish 	    bus[0], bus[1] - bus[0] + 1);
131123c35297Sanish 
131226947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
131326947304SEvan Yan 	    (uint64_t)(bus[1] - bus[0] + 1),
131423c35297Sanish 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
131523c35297Sanish 		DEBUG0("ntbridge: Failed to free a bus number\n");
131623c35297Sanish 		kmem_free(bus, k);
131723c35297Sanish 		return (rc);
131823c35297Sanish 	}
131923c35297Sanish 
132023c35297Sanish 	/*
132123c35297Sanish 	 * Since our resources will be freed at the parent level,
132223c35297Sanish 	 * just reset these values.
132323c35297Sanish 	 */
132423c35297Sanish 	entry->memory_len = 0;
132523c35297Sanish 	entry->io_len = 0;
132623c35297Sanish 	entry->pf_memory_len = 0;
132723c35297Sanish 
132823c35297Sanish 	kmem_free(bus, k);
132923c35297Sanish 
133023c35297Sanish 	/* the following will also free hole data. */
133123c35297Sanish 	return (pcicfg_destroy_phdl(dip));
133223c35297Sanish 
133323c35297Sanish }
133423c35297Sanish 
133523c35297Sanish static int
pcicfg_is_ntbridge(dev_info_t * dip)133623c35297Sanish pcicfg_is_ntbridge(dev_info_t *dip)
133723c35297Sanish {
133823c35297Sanish 	ddi_acc_handle_t	config_handle;
133923c35297Sanish 	uint8_t		class, subclass;
134023c35297Sanish 	int		rc = DDI_SUCCESS;
134123c35297Sanish 
134223c35297Sanish 	if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
134323c35297Sanish 		cmn_err(CE_WARN,
134423c35297Sanish 		    "pcicfg: cannot map config space, to get map type\n");
134523c35297Sanish 		return (DDI_FAILURE);
134623c35297Sanish 	}
134723c35297Sanish 	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
134823c35297Sanish 	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
134923c35297Sanish 
135023c35297Sanish 	/* check for class=6, subclass=9, for non transparent bridges.  */
135123c35297Sanish 	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
135223c35297Sanish 		rc = DDI_FAILURE;
135323c35297Sanish 
135423c35297Sanish 	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
135523c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_VENID),
135623c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_DEVID),
135723c35297Sanish 	    rc);
135823c35297Sanish 	pci_config_teardown(&config_handle);
135923c35297Sanish 	return (rc);
136023c35297Sanish }
136123c35297Sanish 
136223c35297Sanish static uint_t
pcicfg_ntbridge_child(dev_info_t * dip)136323c35297Sanish pcicfg_ntbridge_child(dev_info_t *dip)
136423c35297Sanish {
136523c35297Sanish 	int 		len, val, rc = DDI_FAILURE;
136623c35297Sanish 	dev_info_t	*anode = dip;
136723c35297Sanish 
136823c35297Sanish 	/*
136926947304SEvan Yan 	 * Find the Hotplug Connection (CN) node
137023c35297Sanish 	 */
137123c35297Sanish 	while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
137223c35297Sanish 	    "hp_attachment") != 0)) {
137323c35297Sanish 		anode = ddi_get_parent(anode);
137423c35297Sanish 	}
137523c35297Sanish 
137623c35297Sanish 	if (anode == NULL) {
137723c35297Sanish 		DEBUG0("ntbridge child tree not in PROBE state\n");
137823c35297Sanish 		return (rc);
137923c35297Sanish 	}
138023c35297Sanish 	len = sizeof (int);
138123c35297Sanish 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(anode),
138226947304SEvan Yan 	    DDI_PROP_DONTPASS, PCI_DEV_CONF_MAP_PROP, (caddr_t)&val, &len)
138326947304SEvan Yan 	    != DDI_SUCCESS) {
138423c35297Sanish 
138523c35297Sanish 		DEBUG1("ntbridge child: no \"%s\" property\n",
138623c35297Sanish 		    PCI_DEV_CONF_MAP_PROP);
138723c35297Sanish 		return (rc);
138823c35297Sanish 	}
138923c35297Sanish 	DEBUG0("ntbridge child: success\n");
139023c35297Sanish 	return (DDI_SUCCESS);
139123c35297Sanish }
139223c35297Sanish 
139323c35297Sanish static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)139423c35297Sanish pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
139523c35297Sanish 				uint64_t *boundlen, uint_t space_type)
139623c35297Sanish {
139723c35297Sanish 	int		length, found = DDI_FAILURE, acount, i, ibridge;
139823c35297Sanish 	pci_regspec_t	*assigned;
139923c35297Sanish 
140023c35297Sanish 	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
140123c35297Sanish 		return (found);
140223c35297Sanish 
140326947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
140426947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &length)
140526947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
140623c35297Sanish 		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
140723c35297Sanish 		return (found);
140823c35297Sanish 	}
140923c35297Sanish 	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
141023c35297Sanish 	    ddi_driver_name(dip));
141123c35297Sanish 
141223c35297Sanish 	acount = length / sizeof (pci_regspec_t);
141323c35297Sanish 
141423c35297Sanish 	for (i = 0; i < acount; i++) {
141526947304SEvan Yan 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
141626947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
141723c35297Sanish 		    (space_type == PCI_BASE_SPACE_MEM)) {
141823c35297Sanish 			found = DDI_SUCCESS;
141923c35297Sanish 			break;
142026947304SEvan Yan 		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
142126947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].io_range_bar_offset) &&
142223c35297Sanish 		    (space_type == PCI_BASE_SPACE_IO)) {
142323c35297Sanish 			found = DDI_SUCCESS;
142423c35297Sanish 			break;
142526947304SEvan Yan 		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
142623c35297Sanish 		    pcicfg_indirect_map_devs[ibridge].
142723c35297Sanish 		    prefetch_mem_range_bar_offset) &&
142823c35297Sanish 		    (space_type == (PCI_BASE_SPACE_MEM |
142923c35297Sanish 		    PCI_BASE_PREF_M))) {
143023c35297Sanish 			found = DDI_SUCCESS;
143123c35297Sanish 			break;
143223c35297Sanish 		}
143323c35297Sanish 	}
143423c35297Sanish 	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
143523c35297Sanish 	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
143623c35297Sanish 
143723c35297Sanish 	if (found == DDI_SUCCESS)  {
143823c35297Sanish 		*boundbase = assigned[i].pci_phys_low;
143923c35297Sanish 		*boundlen = assigned[i].pci_size_low;
144023c35297Sanish 	}
144123c35297Sanish 
144223c35297Sanish 	kmem_free(assigned, length);
144323c35297Sanish 	return (found);
144423c35297Sanish }
144523c35297Sanish 
144623c35297Sanish /*
144723c35297Sanish  * This will turn  resources allocated by pcicfg_configure()
144826947304SEvan Yan  * and remove the device tree from the Hotplug Connection (CN)
144923c35297Sanish  * and below.  The routine assumes the devices have their
145023c35297Sanish  * drivers detached.
145123c35297Sanish  */
145223c35297Sanish int
pcicfg_unconfigure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)145326947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
145426947304SEvan Yan     pcicfg_flags_t flags)
145523c35297Sanish {
145623c35297Sanish 	dev_info_t *child_dip;
145723c35297Sanish 	int func;
145823c35297Sanish 	int i;
145926947304SEvan Yan 	int max_function, trans_device;
1460c0da6274SZhi-Jun Robin Fu 	int circ;
1461c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
146226947304SEvan Yan 
146326947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
146426947304SEvan Yan 		max_function = PCICFG_MAX_ARI_FUNCTION;
146526947304SEvan Yan 	else
146626947304SEvan Yan 		max_function = PCI_MAX_FUNCTIONS;
146723c35297Sanish 
146823c35297Sanish 	/*
146923c35297Sanish 	 * Cycle through devices to make sure none are busy.
147023c35297Sanish 	 * If a single device is busy fail the whole unconfigure.
147123c35297Sanish 	 */
1472c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
1473c0da6274SZhi-Jun Robin Fu 
1474c0da6274SZhi-Jun Robin Fu 	ndi_devi_enter(devi, &circ);
147526947304SEvan Yan 	for (func = 0; func < max_function; func++) {
147626947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
147726947304SEvan Yan 			continue;
147826947304SEvan Yan 
147926947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
148026947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
148126947304SEvan Yan 		else
148226947304SEvan Yan 			trans_device = device;
148326947304SEvan Yan 
148426947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device,
148526947304SEvan Yan 		    func & 7)) == NULL)
148623c35297Sanish 			continue;
148723c35297Sanish 
148823c35297Sanish 		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
148923c35297Sanish 			continue;
149026947304SEvan Yan 
149123c35297Sanish 		/*
149223c35297Sanish 		 * Device function is busy. Before returning we have to
149323c35297Sanish 		 * put all functions back online which were taken
149423c35297Sanish 		 * offline during the process.
149523c35297Sanish 		 */
149626947304SEvan Yan 		DEBUG2("Device [0x%x] function [0x%x] is busy\n",
149726947304SEvan Yan 		    trans_device, func & 7);
149826947304SEvan Yan 		/*
149926947304SEvan Yan 		 * If we are only asked to offline one specific function,
150026947304SEvan Yan 		 * and that fails, we just simply return.
150126947304SEvan Yan 		 */
150226947304SEvan Yan 		if (function != PCICFG_ALL_FUNC)
150326947304SEvan Yan 			return (PCICFG_FAILURE);
150426947304SEvan Yan 
150523c35297Sanish 		for (i = 0; i < func; i++) {
150626947304SEvan Yan 			if (max_function == PCICFG_MAX_ARI_FUNCTION)
150726947304SEvan Yan 				trans_device = i >> 3;
150826947304SEvan Yan 
150926947304SEvan Yan 			if ((child_dip = pcicfg_devi_find(devi, trans_device,
151026947304SEvan Yan 			    i & 7)) == NULL) {
151126947304SEvan Yan 				DEBUG0("No more devices to put back "
151226947304SEvan Yan 				    "on line!!\n");
151323c35297Sanish 				/*
151423c35297Sanish 				 * Made it through all functions
151523c35297Sanish 				 */
151623c35297Sanish 				continue;
151723c35297Sanish 			}
151826947304SEvan Yan 			if (ndi_devi_online(child_dip, NDI_CONFIG)
151926947304SEvan Yan 			    != NDI_SUCCESS) {
152023c35297Sanish 				DEBUG0("Failed to put back devices state\n");
1521c0da6274SZhi-Jun Robin Fu 				goto fail;
152223c35297Sanish 			}
152323c35297Sanish 		}
1524c0da6274SZhi-Jun Robin Fu 		goto fail;
152523c35297Sanish 	}
152623c35297Sanish 
152723c35297Sanish 	/*
152826947304SEvan Yan 	 * Now, tear down all devinfo nodes for this Connector.
152923c35297Sanish 	 */
153026947304SEvan Yan 	for (func = 0; func < max_function; func++) {
153126947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
153226947304SEvan Yan 			continue;
153326947304SEvan Yan 
153426947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
153526947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
153626947304SEvan Yan 		else
153726947304SEvan Yan 			trans_device = device;
153826947304SEvan Yan 
153926947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device, func & 7))
154026947304SEvan Yan 		    == NULL) {
154126947304SEvan Yan 			DEBUG2("No device at %x,%x\n", trans_device, func & 7);
154223c35297Sanish 			continue;
154323c35297Sanish 		}
154423c35297Sanish 
154523c35297Sanish 		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
154626947304SEvan Yan 		    trans_device, func & 7);
154723c35297Sanish 
154823c35297Sanish 		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
154923c35297Sanish 			if (pcicfg_ntbridge_unconfigure(child_dip) !=
155023c35297Sanish 			    PCICFG_SUCCESS) {
155123c35297Sanish 				cmn_err(CE_WARN,
155223c35297Sanish 				    "ntbridge: unconfigure failed\n");
1553c0da6274SZhi-Jun Robin Fu 				goto fail;
155423c35297Sanish 			}
155523c35297Sanish 
1556c0da6274SZhi-Jun Robin Fu 		if (pcicfg_teardown_device(child_dip, flags, is_pcie)
155726947304SEvan Yan 		    != PCICFG_SUCCESS) {
155823c35297Sanish 			DEBUG2("Failed to tear down device [0x%x]"
155926947304SEvan Yan 			    "function [0x%x]\n", trans_device, func & 7);
1560c0da6274SZhi-Jun Robin Fu 			goto fail;
156123c35297Sanish 		}
156223c35297Sanish 	}
156326947304SEvan Yan 
156426947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
156526947304SEvan Yan 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
156626947304SEvan Yan 		(void) pcie_ari_disable(devi);
156726947304SEvan Yan 	}
156826947304SEvan Yan 
1569c0da6274SZhi-Jun Robin Fu 	ndi_devi_exit(devi, circ);
157023c35297Sanish 	return (PCICFG_SUCCESS);
1571c0da6274SZhi-Jun Robin Fu 
1572c0da6274SZhi-Jun Robin Fu fail:
1573c0da6274SZhi-Jun Robin Fu 	ndi_devi_exit(devi, circ);
1574c0da6274SZhi-Jun Robin Fu 	return (PCICFG_FAILURE);
157523c35297Sanish }
157623c35297Sanish 
157723c35297Sanish static int
pcicfg_teardown_device(dev_info_t * dip,pcicfg_flags_t flags,boolean_t is_pcie)1578c0da6274SZhi-Jun Robin Fu pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
157923c35297Sanish {
158023c35297Sanish 	ddi_acc_handle_t	handle;
158123c35297Sanish 
158223c35297Sanish 	/*
158323c35297Sanish 	 * Free up resources associated with 'dip'
158423c35297Sanish 	 */
158526947304SEvan Yan 	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
158623c35297Sanish 		DEBUG0("Failed to free resources\n");
158723c35297Sanish 		return (PCICFG_FAILURE);
158823c35297Sanish 	}
158923c35297Sanish 
159023c35297Sanish 	/*
159123c35297Sanish 	 * disable the device
159223c35297Sanish 	 */
159323c35297Sanish 	if (pcicfg_config_setup(dip, &handle) != PCICFG_SUCCESS)
159423c35297Sanish 		return (PCICFG_FAILURE);
159523c35297Sanish 	pcicfg_device_off(handle);
159623c35297Sanish 	pcicfg_config_teardown(&handle);
159723c35297Sanish 
1598c0da6274SZhi-Jun Robin Fu 	if (is_pcie) {
1599c0da6274SZhi-Jun Robin Fu 		/*
1600c0da6274SZhi-Jun Robin Fu 		 * free pcie_bus_t for the sub-tree
1601c0da6274SZhi-Jun Robin Fu 		 */
1602c0da6274SZhi-Jun Robin Fu 		if (ddi_get_child(dip) != NULL)
1603c0da6274SZhi-Jun Robin Fu 			pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
1604c0da6274SZhi-Jun Robin Fu 
1605c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(dip, PCIE_BUS_ALL);
1606c0da6274SZhi-Jun Robin Fu 	}
1607c0da6274SZhi-Jun Robin Fu 
160823c35297Sanish 	/*
160923c35297Sanish 	 * The framework provides this routine which can
161023c35297Sanish 	 * tear down a sub-tree.
161123c35297Sanish 	 */
161223c35297Sanish 	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
161323c35297Sanish 		DEBUG0("Failed to offline and remove node\n");
161423c35297Sanish 		return (PCICFG_FAILURE);
161523c35297Sanish 	}
161623c35297Sanish 
161723c35297Sanish 	return (PCICFG_SUCCESS);
161823c35297Sanish }
161923c35297Sanish 
162023c35297Sanish /*
162123c35297Sanish  * BEGIN GENERIC SUPPORT ROUTINES
162223c35297Sanish  */
162323c35297Sanish static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)162423c35297Sanish pcicfg_find_phdl(dev_info_t *dip)
162523c35297Sanish {
162623c35297Sanish 	pcicfg_phdl_t *entry;
162723c35297Sanish 	mutex_enter(&pcicfg_list_mutex);
162823c35297Sanish 	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
162923c35297Sanish 		if (entry->dip == dip) {
163023c35297Sanish 			mutex_exit(&pcicfg_list_mutex);
163123c35297Sanish 			return (entry);
163223c35297Sanish 		}
163323c35297Sanish 	}
163423c35297Sanish 	mutex_exit(&pcicfg_list_mutex);
163523c35297Sanish 
163623c35297Sanish 	/*
163723c35297Sanish 	 * Did'nt find entry - create one
163823c35297Sanish 	 */
163923c35297Sanish 	return (pcicfg_create_phdl(dip));
164023c35297Sanish }
164123c35297Sanish 
164223c35297Sanish static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)164323c35297Sanish pcicfg_create_phdl(dev_info_t *dip)
164423c35297Sanish {
164523c35297Sanish 	pcicfg_phdl_t *new;
164623c35297Sanish 
164726947304SEvan Yan 	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), KM_SLEEP);
164823c35297Sanish 
164923c35297Sanish 	new->dip = dip;
165023c35297Sanish 	mutex_enter(&pcicfg_list_mutex);
165123c35297Sanish 	new->next = pcicfg_phdl_list;
165223c35297Sanish 	pcicfg_phdl_list = new;
165323c35297Sanish 	mutex_exit(&pcicfg_list_mutex);
165423c35297Sanish 
165523c35297Sanish 	return (new);
165623c35297Sanish }
165723c35297Sanish 
165823c35297Sanish static int
pcicfg_destroy_phdl(dev_info_t * dip)165923c35297Sanish pcicfg_destroy_phdl(dev_info_t *dip)
166023c35297Sanish {
166123c35297Sanish 	pcicfg_phdl_t *entry;
166223c35297Sanish 	pcicfg_phdl_t *follow = NULL;
166323c35297Sanish 
166423c35297Sanish 	mutex_enter(&pcicfg_list_mutex);
166523c35297Sanish 	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
166623c35297Sanish 	    entry = entry->next) {
166723c35297Sanish 		if (entry->dip == dip) {
166823c35297Sanish 			if (entry == pcicfg_phdl_list) {
166923c35297Sanish 				pcicfg_phdl_list = entry->next;
167023c35297Sanish 			} else {
167123c35297Sanish 				follow->next = entry->next;
167223c35297Sanish 			}
167323c35297Sanish 			/*
167423c35297Sanish 			 * If this entry has any allocated memory
167523c35297Sanish 			 * or IO space associated with it, that
167623c35297Sanish 			 * must be freed up.
167723c35297Sanish 			 */
167823c35297Sanish 			if (entry->memory_len > 0) {
167923c35297Sanish 				(void) ndi_ra_free(ddi_get_parent(dip),
168026947304SEvan Yan 				    entry->memory_base, entry->memory_len,
168123c35297Sanish 				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
168223c35297Sanish 			}
168323c35297Sanish 			pcicfg_free_hole(&entry->mem_hole);
168423c35297Sanish 
168523c35297Sanish 			if (entry->io_len > 0) {
168623c35297Sanish 				(void) ndi_ra_free(ddi_get_parent(dip),
168726947304SEvan Yan 				    entry->io_base, entry->io_len,
168823c35297Sanish 				    NDI_RA_TYPE_IO, NDI_RA_PASS);
168923c35297Sanish 			}
169023c35297Sanish 			pcicfg_free_hole(&entry->io_hole);
169123c35297Sanish 
169223c35297Sanish 			if (entry->pf_memory_len > 0) {
169323c35297Sanish 				(void) ndi_ra_free(ddi_get_parent(dip),
169426947304SEvan Yan 				    entry->pf_memory_base, entry->pf_memory_len,
169526947304SEvan Yan 				    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
169623c35297Sanish 			}
169723c35297Sanish 			pcicfg_free_hole(&entry->pf_mem_hole);
169823c35297Sanish 
169923c35297Sanish 			/*
170023c35297Sanish 			 * Destroy this entry
170123c35297Sanish 			 */
170223c35297Sanish 			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
170323c35297Sanish 			mutex_exit(&pcicfg_list_mutex);
170423c35297Sanish 			return (PCICFG_SUCCESS);
170523c35297Sanish 		}
170623c35297Sanish 	}
170723c35297Sanish 	mutex_exit(&pcicfg_list_mutex);
170823c35297Sanish 	/*
170923c35297Sanish 	 * Did'nt find the entry
171023c35297Sanish 	 */
171123c35297Sanish 	return (PCICFG_FAILURE);
171223c35297Sanish }
171323c35297Sanish 
171423c35297Sanish static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)171523c35297Sanish pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
171623c35297Sanish {
171723c35297Sanish 	ddi_acc_handle_t handle;
171823c35297Sanish 	pci_regspec_t *reg;
171923c35297Sanish 	int length;
172023c35297Sanish 	int rcount;
172123c35297Sanish 	int i;
172223c35297Sanish 	int offset;
172323c35297Sanish 	uint64_t mem_answer;
172423c35297Sanish 	uint32_t io_answer;
172523c35297Sanish 	int count;
172623c35297Sanish 	uint8_t header_type;
172723c35297Sanish 	ppb_ranges_t range[PCICFG_RANGE_LEN];
172823c35297Sanish 	int bus_range[2];
172923c35297Sanish 	uint64_t mem_residual;
173023c35297Sanish 	uint64_t pf_mem_residual;
173123c35297Sanish 	uint64_t io_residual;
173223c35297Sanish 
173323c35297Sanish 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
173423c35297Sanish 
173526947304SEvan Yan 	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
173623c35297Sanish 
173723c35297Sanish 	entry->error = PCICFG_SUCCESS;
173823c35297Sanish 
173923c35297Sanish 	if (entry == NULL) {
174023c35297Sanish 		DEBUG0("Failed to get entry\n");
174123c35297Sanish 		entry->error = PCICFG_FAILURE;
174223c35297Sanish 		return (DDI_WALK_TERMINATE);
174323c35297Sanish 	}
174423c35297Sanish 
174526947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
174623c35297Sanish 		DEBUG0("Failed to map config space!\n");
174723c35297Sanish 		entry->error = PCICFG_FAILURE;
174823c35297Sanish 		return (DDI_WALK_TERMINATE);
174923c35297Sanish 	}
175023c35297Sanish 
175123c35297Sanish 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
175223c35297Sanish 
175323c35297Sanish 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
175423c35297Sanish 
175526947304SEvan Yan 		bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
175623c35297Sanish 
175723c35297Sanish 		(void) pcicfg_setup_bridge(entry, handle);
175823c35297Sanish 
175923c35297Sanish 		range[0].child_high = range[0].parent_high |=
176023c35297Sanish 		    (PCI_REG_REL_M | PCI_ADDR_IO);
176126947304SEvan Yan 		range[0].child_low = range[0].parent_low = entry->io_last;
176223c35297Sanish 		range[1].child_high = range[1].parent_high |=
176323c35297Sanish 		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
176423c35297Sanish 		range[1].child_low = range[1].parent_low =
176523c35297Sanish 		    entry->memory_last;
176623c35297Sanish 		range[2].child_high = range[2].parent_high |=
176723c35297Sanish 		    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
176823c35297Sanish 		range[2].child_low = range[2].parent_low =
176923c35297Sanish 		    entry->pf_memory_last;
177023c35297Sanish 
177123c35297Sanish 		ndi_devi_enter(dip, &count);
177223c35297Sanish 		ddi_walk_devs(ddi_get_child(dip),
177323c35297Sanish 		    pcicfg_bridge_assign, (void *)entry);
177423c35297Sanish 		ndi_devi_exit(dip, count);
177523c35297Sanish 
177623c35297Sanish 		(void) pcicfg_update_bridge(entry, handle);
177723c35297Sanish 
177823c35297Sanish 		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
177923c35297Sanish 		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
178023c35297Sanish 
178123c35297Sanish 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
178223c35297Sanish 		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
178323c35297Sanish 			DEBUG0("Failed to set bus-range property");
178423c35297Sanish 			entry->error = PCICFG_FAILURE;
17851fb5b786Sprasad 			(void) pcicfg_config_teardown(&handle);
178623c35297Sanish 			return (DDI_WALK_TERMINATE);
178723c35297Sanish 		}
178823c35297Sanish 
178923c35297Sanish 		/*
179023c35297Sanish 		 * Put back memory and I/O space not allocated
179123c35297Sanish 		 * under the bridge.
179223c35297Sanish 		 */
179323c35297Sanish 		mem_residual = entry->memory_len -
179423c35297Sanish 		    (entry->memory_last - entry->memory_base);
179523c35297Sanish 		if (mem_residual > 0) {
179623c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(dip),
179726947304SEvan Yan 			    entry->memory_last, mem_residual,
179823c35297Sanish 			    NDI_RA_TYPE_MEM, NDI_RA_PASS);
179923c35297Sanish 		}
180023c35297Sanish 
180126947304SEvan Yan 		io_residual = entry->io_len - (entry->io_last - entry->io_base);
180223c35297Sanish 		if (io_residual > 0) {
180326947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(dip), entry->io_last,
180426947304SEvan Yan 			    io_residual, NDI_RA_TYPE_IO, NDI_RA_PASS);
180523c35297Sanish 		}
180623c35297Sanish 
180723c35297Sanish 		pf_mem_residual = entry->pf_memory_len -
180823c35297Sanish 		    (entry->pf_memory_last - entry->pf_memory_base);
180923c35297Sanish 		if (pf_mem_residual > 0) {
181023c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(dip),
181126947304SEvan Yan 			    entry->pf_memory_last, pf_mem_residual,
181223c35297Sanish 			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
181323c35297Sanish 		}
181423c35297Sanish 
181523c35297Sanish 		if (entry->io_len > 0) {
181623c35297Sanish 			range[0].size_low = entry->io_last - entry->io_base;
181723c35297Sanish 			if (pcicfg_update_ranges_prop(dip, &range[0])) {
181823c35297Sanish 				DEBUG0("Failed to update ranges (i/o)\n");
181923c35297Sanish 				entry->error = PCICFG_FAILURE;
18201fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
182123c35297Sanish 				return (DDI_WALK_TERMINATE);
182223c35297Sanish 			}
182323c35297Sanish 		}
182423c35297Sanish 		if (entry->memory_len > 0) {
182523c35297Sanish 			range[1].size_low =
182623c35297Sanish 			    entry->memory_last - entry->memory_base;
182723c35297Sanish 			if (pcicfg_update_ranges_prop(dip, &range[1])) {
182823c35297Sanish 				DEBUG0("Failed to update ranges (memory)\n");
182923c35297Sanish 				entry->error = PCICFG_FAILURE;
18301fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
183123c35297Sanish 				return (DDI_WALK_TERMINATE);
183223c35297Sanish 			}
183323c35297Sanish 		}
183423c35297Sanish 		if (entry->pf_memory_len > 0) {
183523c35297Sanish 			range[2].size_low =
183623c35297Sanish 			    entry->pf_memory_last - entry->pf_memory_base;
183723c35297Sanish 			if (pcicfg_update_ranges_prop(dip, &range[2])) {
183823c35297Sanish 				DEBUG0("Failed to update ranges (PF memory)\n");
183923c35297Sanish 				entry->error = PCICFG_FAILURE;
18401fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
184123c35297Sanish 				return (DDI_WALK_TERMINATE);
184223c35297Sanish 			}
184323c35297Sanish 		}
184423c35297Sanish 
184523c35297Sanish 		(void) pcicfg_device_on(handle);
184623c35297Sanish 
184723c35297Sanish 		PCICFG_DUMP_BRIDGE_CONFIG(handle);
184823c35297Sanish 
18491fb5b786Sprasad 		(void) pcicfg_config_teardown(&handle);
18501fb5b786Sprasad 
185123c35297Sanish 		return (DDI_WALK_PRUNECHILD);
185223c35297Sanish 	}
185323c35297Sanish 
185423c35297Sanish 	/*
185523c35297Sanish 	 * If there is an interrupt pin set program
185623c35297Sanish 	 * interrupt line with default values.
185723c35297Sanish 	 */
185823c35297Sanish 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
185923c35297Sanish 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
186023c35297Sanish 	}
186123c35297Sanish 
186223c35297Sanish 	/*
186323c35297Sanish 	 * A single device (under a bridge).
186423c35297Sanish 	 * For each "reg" property with a length, allocate memory
186523c35297Sanish 	 * and program the base registers.
186623c35297Sanish 	 */
186726947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
186826947304SEvan Yan 	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
186923c35297Sanish 		DEBUG0("Failed to read reg property\n");
187023c35297Sanish 		entry->error = PCICFG_FAILURE;
18711fb5b786Sprasad 		(void) pcicfg_config_teardown(&handle);
187223c35297Sanish 		return (DDI_WALK_TERMINATE);
187323c35297Sanish 	}
187423c35297Sanish 
187523c35297Sanish 	rcount = length / sizeof (pci_regspec_t);
187623c35297Sanish 	offset = PCI_CONF_BASE0;
187723c35297Sanish 	for (i = 0; i < rcount; i++) {
187826947304SEvan Yan 		if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
187923c35297Sanish 
188023c35297Sanish 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
188123c35297Sanish 
188223c35297Sanish 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
188323c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
188423c35297Sanish 
188523c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
188623c35297Sanish 					/* allocate prefetchable memory */
188723c35297Sanish 					pcicfg_get_pf_mem(entry,
188823c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
188923c35297Sanish 				} else { /* get non prefetchable memory */
189023c35297Sanish 					pcicfg_get_mem(entry,
189123c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
189223c35297Sanish 				}
189323c35297Sanish 				pci_config_put64(handle, offset, mem_answer);
189423c35297Sanish 				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
189526947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
189623c35297Sanish 				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
189723c35297Sanish 				    offset + 4,
189823c35297Sanish 				    pci_config_get32(handle, offset + 4));
189923c35297Sanish 
190023c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
190123c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(mem_answer);
190226947304SEvan Yan 				reg[i].pci_phys_mid = PCICFG_HIADDR(mem_answer);
190323c35297Sanish 				break;
190423c35297Sanish 
190523c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
190623c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
190723c35297Sanish 					/* allocate prefetchable memory */
190823c35297Sanish 					pcicfg_get_pf_mem(entry,
190923c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
191023c35297Sanish 				} else {
191123c35297Sanish 					/* get non prefetchable memory */
191223c35297Sanish 					pcicfg_get_mem(entry,
191323c35297Sanish 					    reg[i].pci_size_low, &mem_answer);
191423c35297Sanish 				}
191523c35297Sanish 
191626947304SEvan Yan 				pci_config_put32(handle, offset,
191726947304SEvan Yan 				    (uint32_t)mem_answer);
191823c35297Sanish 
191923c35297Sanish 				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
192026947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
192123c35297Sanish 
192223c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
192323c35297Sanish 				reg[i].pci_phys_low = (uint32_t)mem_answer;
192423c35297Sanish 
192523c35297Sanish 				break;
192623c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
192723c35297Sanish 				/* allocate I/O space from the allocator */
192823c35297Sanish 
192926947304SEvan Yan 				(void) pcicfg_get_io(entry, reg[i].pci_size_low,
193026947304SEvan Yan 				    &io_answer);
193123c35297Sanish 				pci_config_put32(handle, offset, io_answer);
193223c35297Sanish 
193323c35297Sanish 				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
193426947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
193523c35297Sanish 
193623c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
193723c35297Sanish 				reg[i].pci_phys_low = io_answer;
193823c35297Sanish 
193923c35297Sanish 				break;
194023c35297Sanish 			default:
194123c35297Sanish 				DEBUG0("Unknown register type\n");
194223c35297Sanish 				kmem_free(reg, length);
194323c35297Sanish 				(void) pcicfg_config_teardown(&handle);
194423c35297Sanish 				entry->error = PCICFG_FAILURE;
194523c35297Sanish 				return (DDI_WALK_TERMINATE);
194623c35297Sanish 			} /* switch */
194723c35297Sanish 
194823c35297Sanish 			/*
194923c35297Sanish 			 * Now that memory locations are assigned,
195023c35297Sanish 			 * update the assigned address property.
195123c35297Sanish 			 */
195226947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip, &reg[i])
195326947304SEvan Yan 			    != PCICFG_SUCCESS) {
195423c35297Sanish 				kmem_free(reg, length);
195523c35297Sanish 				(void) pcicfg_config_teardown(&handle);
195623c35297Sanish 				entry->error = PCICFG_FAILURE;
195723c35297Sanish 				return (DDI_WALK_TERMINATE);
195823c35297Sanish 			}
195923c35297Sanish 		}
196023c35297Sanish 	}
196123c35297Sanish 	(void) pcicfg_device_on(handle);
196223c35297Sanish 
196323c35297Sanish 	PCICFG_DUMP_DEVICE_CONFIG(handle);
196423c35297Sanish 
196523c35297Sanish 	(void) pcicfg_config_teardown(&handle);
196623c35297Sanish 	kmem_free((caddr_t)reg, length);
196723c35297Sanish 	return (DDI_WALK_CONTINUE);
196823c35297Sanish }
196923c35297Sanish 
197023c35297Sanish static int
pcicfg_device_assign(dev_info_t * dip)197123c35297Sanish pcicfg_device_assign(dev_info_t *dip)
197223c35297Sanish {
197323c35297Sanish 	ddi_acc_handle_t	handle;
197423c35297Sanish 	pci_regspec_t		*reg;
197523c35297Sanish 	int			length;
197623c35297Sanish 	int			rcount;
197723c35297Sanish 	int			i;
197823c35297Sanish 	int			offset;
197923c35297Sanish 	ndi_ra_request_t	request;
198023c35297Sanish 	uint64_t		answer;
198123c35297Sanish 	uint64_t		alen;
198223c35297Sanish 
198323c35297Sanish 	DEBUG1("%llx now under configuration\n", dip);
198423c35297Sanish 
198523c35297Sanish 	/* request.ra_len = PCICFG_ROUND_UP(request.ra_len, PCICFG_IOGRAN); */
198623c35297Sanish 	if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
198723c35297Sanish 
198823c35297Sanish 		return (pcicfg_ntbridge_program_child(dip));
198923c35297Sanish 	}
199023c35297Sanish 	/*
199123c35297Sanish 	 * XXX Failure here should be noted
199223c35297Sanish 	 */
199326947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
199426947304SEvan Yan 	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
199523c35297Sanish 		DEBUG0("Failed to read reg property\n");
199623c35297Sanish 		return (PCICFG_FAILURE);
199723c35297Sanish 	}
199823c35297Sanish 
199923c35297Sanish 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
200023c35297Sanish 		DEBUG0("Failed to map config space!\n");
20011fb5b786Sprasad 		kmem_free(reg, length);
200223c35297Sanish 		return (PCICFG_FAILURE);
200323c35297Sanish 	}
200423c35297Sanish 
200523c35297Sanish 	/*
200623c35297Sanish 	 * A single device
200723c35297Sanish 	 *
200823c35297Sanish 	 * For each "reg" property with a length, allocate memory
200923c35297Sanish 	 * and program the base registers.
201023c35297Sanish 	 */
201123c35297Sanish 
201223c35297Sanish 	/*
201323c35297Sanish 	 * If there is an interrupt pin set program
201423c35297Sanish 	 * interrupt line with default values.
201523c35297Sanish 	 */
201623c35297Sanish 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
201723c35297Sanish 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
201823c35297Sanish 	}
201923c35297Sanish 
202023c35297Sanish 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
202123c35297Sanish 
202223c35297Sanish 	/*
202323c35297Sanish 	 * Note: Both non-prefetchable and prefetchable memory space
202423c35297Sanish 	 * allocations are made within 32bit space. Currently, BIOSs
202523c35297Sanish 	 * allocate device memory for PCI devices within the 32bit space
202623c35297Sanish 	 * so this will not be a problem.
202723c35297Sanish 	 */
202823c35297Sanish 	request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED;
202923c35297Sanish 	request.ra_boundbase = 0;
203023c35297Sanish 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
203123c35297Sanish 
203223c35297Sanish 	rcount = length / sizeof (pci_regspec_t);
203323c35297Sanish 	offset = PCI_CONF_BASE0;
203423c35297Sanish 	for (i = 0; i < rcount; i++) {
203523c35297Sanish 		char	*mem_type;
203623c35297Sanish 
203726947304SEvan Yan 		if ((reg[i].pci_size_low != 0)|| (reg[i].pci_size_hi != 0)) {
203823c35297Sanish 
203923c35297Sanish 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
204023c35297Sanish 			request.ra_len = reg[i].pci_size_low;
204123c35297Sanish 
204223c35297Sanish 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
204323c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
204423c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
204523c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
204623c35297Sanish 				} else {
204723c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
204823c35297Sanish 				}
204923c35297Sanish 				/* allocate memory space from the allocator */
205026947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
205126947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
205226947304SEvan Yan 				    != NDI_SUCCESS) {
205323c35297Sanish 					DEBUG0("Failed to allocate 64b mem\n");
205423c35297Sanish 					kmem_free(reg, length);
205523c35297Sanish 					(void) pcicfg_config_teardown(&handle);
20565af4ae46Sjveta 					return (PCICFG_NORESRC);
205723c35297Sanish 				}
205823c35297Sanish 				DEBUG3("64 addr = [0x%x.0x%x] len [0x%x]\n",
205923c35297Sanish 				    PCICFG_HIADDR(answer),
206026947304SEvan Yan 				    PCICFG_LOADDR(answer), alen);
206123c35297Sanish 				/* program the low word */
206226947304SEvan Yan 				pci_config_put32(handle, offset,
206326947304SEvan Yan 				    PCICFG_LOADDR(answer));
206423c35297Sanish 				/* program the high word */
206523c35297Sanish 				pci_config_put32(handle, offset + 4,
206623c35297Sanish 				    PCICFG_HIADDR(answer));
206723c35297Sanish 
206823c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
206923c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
207023c35297Sanish 				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
207123c35297Sanish 				/*
207223c35297Sanish 				 * currently support 32b address space
207323c35297Sanish 				 * assignments only.
207423c35297Sanish 				 */
207526947304SEvan Yan 				reg[i].pci_phys_hi ^=
207626947304SEvan Yan 				    PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
207723c35297Sanish 
207823c35297Sanish 				offset += 8;
207923c35297Sanish 				break;
208023c35297Sanish 
208123c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
208223c35297Sanish 				if (reg[i].pci_phys_hi & PCI_REG_PF_M)
208323c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
208423c35297Sanish 				else
208523c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
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 32b mem\n");
209123c35297Sanish 					kmem_free(reg, length);
209223c35297Sanish 					(void) pcicfg_config_teardown(&handle);
20935af4ae46Sjveta 					return (PCICFG_NORESRC);
209423c35297Sanish 				}
209523c35297Sanish 				DEBUG3("32 addr = [0x%x.0x%x] len [0x%x]\n",
209623c35297Sanish 				    PCICFG_HIADDR(answer),
209723c35297Sanish 				    PCICFG_LOADDR(answer),
209823c35297Sanish 				    alen);
209923c35297Sanish 				/* program the low word */
210026947304SEvan Yan 				pci_config_put32(handle, offset,
210126947304SEvan Yan 				    PCICFG_LOADDR(answer));
210223c35297Sanish 
210323c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
210423c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
210523c35297Sanish 				reg[i].pci_phys_mid = 0;
210623c35297Sanish 
210723c35297Sanish 				offset += 4;
210823c35297Sanish 				break;
210923c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
2110b9abf428Slipeng sang - Sun Microsystems - Beijing China 				/*
2111b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * Try to allocate I/O space. If it fails,
2112b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * continue here instead of returning failure
2113b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * so that the hotplug for drivers that don't
2114b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * use I/O space can succeed, For drivers
2115b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * that need to use I/O space, the hotplug
2116b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * will still fail later during driver attach.
2117b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 */
211826947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
211926947304SEvan Yan 				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
212023c35297Sanish 				    != NDI_SUCCESS) {
212123c35297Sanish 					DEBUG0("Failed to allocate I/O\n");
2122b9abf428Slipeng sang - Sun Microsystems - Beijing China 					continue;
212323c35297Sanish 				}
212423c35297Sanish 				DEBUG3("I/O addr = [0x%x.0x%x] len [0x%x]\n",
212523c35297Sanish 				    PCICFG_HIADDR(answer),
212626947304SEvan Yan 				    PCICFG_LOADDR(answer), alen);
212726947304SEvan Yan 				pci_config_put32(handle, offset,
212826947304SEvan Yan 				    PCICFG_LOADDR(answer));
212923c35297Sanish 
213023c35297Sanish 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
213123c35297Sanish 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
213223c35297Sanish 
213323c35297Sanish 				offset += 4;
213423c35297Sanish 				break;
213523c35297Sanish 			default:
213623c35297Sanish 				DEBUG0("Unknown register type\n");
213723c35297Sanish 				kmem_free(reg, length);
213823c35297Sanish 				(void) pcicfg_config_teardown(&handle);
213923c35297Sanish 				return (PCICFG_FAILURE);
214023c35297Sanish 			} /* switch */
214123c35297Sanish 
214223c35297Sanish 			/*
214323c35297Sanish 			 * Now that memory locations are assigned,
214423c35297Sanish 			 * update the assigned address property.
214523c35297Sanish 			 */
214623c35297Sanish 
214726947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip, &reg[i])
214826947304SEvan Yan 			    != PCICFG_SUCCESS) {
214923c35297Sanish 				kmem_free(reg, length);
215023c35297Sanish 				(void) pcicfg_config_teardown(&handle);
215123c35297Sanish 				return (PCICFG_FAILURE);
215223c35297Sanish 			}
215323c35297Sanish 		}
215423c35297Sanish 	}
215523c35297Sanish 
215623c35297Sanish 	(void) pcicfg_device_on(handle);
215723c35297Sanish 	kmem_free(reg, length);
215823c35297Sanish 
215923c35297Sanish 	PCICFG_DUMP_DEVICE_CONFIG(handle);
216023c35297Sanish 
216123c35297Sanish 	(void) pcicfg_config_teardown(&handle);
216223c35297Sanish 	return (PCICFG_SUCCESS);
216323c35297Sanish }
216423c35297Sanish 
216526947304SEvan Yan static int
pcicfg_device_assign_readonly(dev_info_t * dip)216626947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip)
216726947304SEvan Yan {
216826947304SEvan Yan 	ddi_acc_handle_t	handle;
216926947304SEvan Yan 	pci_regspec_t		*assigned;
217026947304SEvan Yan 	int			length;
217126947304SEvan Yan 	int			acount;
217226947304SEvan Yan 	int			i;
217326947304SEvan Yan 	ndi_ra_request_t	request;
217426947304SEvan Yan 	uint64_t		answer;
217526947304SEvan Yan 	uint64_t		alen;
217626947304SEvan Yan 
217726947304SEvan Yan 	DEBUG1("%llx now under configuration\n", dip);
217826947304SEvan Yan 
217926947304SEvan Yan 	/*
218026947304SEvan Yan 	 * we don't support ntbridges for readonly probe.
218126947304SEvan Yan 	 */
218226947304SEvan Yan 	if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
218326947304SEvan Yan 		return (PCICFG_FAILURE);
218426947304SEvan Yan 	}
218526947304SEvan Yan 
218626947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
218726947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
218826947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
218926947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
219026947304SEvan Yan 		return (PCICFG_FAILURE);
219126947304SEvan Yan 	}
219226947304SEvan Yan 
219326947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
219426947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
219526947304SEvan Yan 		kmem_free(assigned, length);
219626947304SEvan Yan 		return (PCICFG_FAILURE);
219726947304SEvan Yan 	}
219826947304SEvan Yan 
219926947304SEvan Yan 	/*
220026947304SEvan Yan 	 * If there is an interrupt pin set program
220126947304SEvan Yan 	 * interrupt line with default values.
220226947304SEvan Yan 	 */
220326947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
220426947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
220526947304SEvan Yan 	}
220626947304SEvan Yan 	/*
220726947304SEvan Yan 	 * Note: Both non-prefetchable and prefetchable memory space
220826947304SEvan Yan 	 * allocations are made within 32bit space. Currently, BIOSs
220926947304SEvan Yan 	 * allocate device memory for PCI devices within the 32bit space
221026947304SEvan Yan 	 * so this will not be a problem.
221126947304SEvan Yan 	 */
221226947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
221326947304SEvan Yan 
221426947304SEvan Yan 	request.ra_flags = NDI_RA_ALLOC_SPECIFIED;  /* specified addr */
221526947304SEvan Yan 	request.ra_boundbase = 0;
221626947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
221726947304SEvan Yan 
221826947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
221926947304SEvan Yan 	for (i = 0; i < acount; i++) {
222026947304SEvan Yan 		char	*mem_type;
222126947304SEvan Yan 
222226947304SEvan Yan 		if ((assigned[i].pci_size_low != 0)||
222326947304SEvan Yan 		    (assigned[i].pci_size_hi != 0)) {
222426947304SEvan Yan 
222526947304SEvan Yan 			request.ra_len = assigned[i].pci_size_low;
222626947304SEvan Yan 
222726947304SEvan Yan 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
222826947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
222926947304SEvan Yan 				request.ra_addr = (uint64_t)PCICFG_LADDR(
223026947304SEvan Yan 				    assigned[i].pci_phys_low,
223126947304SEvan Yan 				    assigned[i].pci_phys_mid);
223226947304SEvan Yan 
223326947304SEvan Yan 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M) {
223426947304SEvan Yan 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
223526947304SEvan Yan 				} else {
223626947304SEvan Yan 					mem_type = NDI_RA_TYPE_MEM;
223726947304SEvan Yan 				}
223826947304SEvan Yan 				/* allocate memory space from the allocator */
223926947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
224026947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
224126947304SEvan Yan 				    != NDI_SUCCESS) {
224226947304SEvan Yan 					DEBUG0("Failed to allocate 64b mem\n");
224326947304SEvan Yan 					kmem_free(assigned, length);
224426947304SEvan Yan 					return (PCICFG_NORESRC);
224526947304SEvan Yan 				}
224626947304SEvan Yan 
224726947304SEvan Yan 				break;
224826947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
224926947304SEvan Yan 				request.ra_addr = (uint64_t)
225026947304SEvan Yan 				    assigned[i].pci_phys_low;
225126947304SEvan Yan 
225226947304SEvan Yan 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
225326947304SEvan Yan 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
225426947304SEvan Yan 				else
225526947304SEvan Yan 					mem_type = NDI_RA_TYPE_MEM;
225626947304SEvan Yan 				/* allocate memory space from the allocator */
225726947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
225826947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
225926947304SEvan Yan 				    != NDI_SUCCESS) {
226026947304SEvan Yan 					DEBUG0("Failed to allocate 32b mem\n");
226126947304SEvan Yan 					kmem_free(assigned, length);
226226947304SEvan Yan 					return (PCICFG_NORESRC);
226326947304SEvan Yan 				}
226426947304SEvan Yan 
226526947304SEvan Yan 				break;
226626947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
226726947304SEvan Yan 				request.ra_addr = (uint64_t)
226826947304SEvan Yan 				    assigned[i].pci_phys_low;
226926947304SEvan Yan 
227026947304SEvan Yan 				/* allocate I/O space from the allocator */
227126947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
227226947304SEvan Yan 				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
227326947304SEvan Yan 				    != NDI_SUCCESS) {
227426947304SEvan Yan 					DEBUG0("Failed to allocate I/O\n");
227526947304SEvan Yan 					kmem_free(assigned, length);
227626947304SEvan Yan 					return (PCICFG_NORESRC);
227726947304SEvan Yan 				}
227826947304SEvan Yan 
227926947304SEvan Yan 				break;
228026947304SEvan Yan 			default:
228126947304SEvan Yan 				DEBUG0("Unknown register type\n");
228226947304SEvan Yan 				kmem_free(assigned, length);
228326947304SEvan Yan 				return (PCICFG_FAILURE);
228426947304SEvan Yan 			} /* switch */
228526947304SEvan Yan 		}
228626947304SEvan Yan 	}
228726947304SEvan Yan 
228826947304SEvan Yan 	(void) pcicfg_device_on(handle);
228926947304SEvan Yan 	kmem_free(assigned, length);
229026947304SEvan Yan 
229126947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
229226947304SEvan Yan 
229326947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
229426947304SEvan Yan 	return (PCICFG_SUCCESS);
229526947304SEvan Yan }
229626947304SEvan Yan 
229723c35297Sanish #ifdef	DEBUG
229823c35297Sanish /*
229923c35297Sanish  * This function is useful in debug mode, where we can measure how
230023c35297Sanish  * much memory was wasted/unallocated in bridge device's domain.
230123c35297Sanish  */
230223c35297Sanish static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)230323c35297Sanish pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
230423c35297Sanish {
230523c35297Sanish 	uint64_t len = 0;
230623c35297Sanish 	uint32_t count = 0;
230723c35297Sanish 
230823c35297Sanish 	do {
230923c35297Sanish 		len += hole->len;
231023c35297Sanish 		hole = hole->next;
231123c35297Sanish 		count++;
231223c35297Sanish 	} while (hole);
231323c35297Sanish 	*hole_count = count;
231423c35297Sanish 	return (len);
231523c35297Sanish }
231623c35297Sanish #endif
231723c35297Sanish 
231823c35297Sanish /*
231923c35297Sanish  * This function frees data structures that hold the hole information
232023c35297Sanish  * which are allocated in pcicfg_alloc_hole(). This is not freeing
232123c35297Sanish  * any memory allocated through NDI calls.
232223c35297Sanish  */
232323c35297Sanish static void
pcicfg_free_hole(hole_t * addr_hole)232423c35297Sanish pcicfg_free_hole(hole_t *addr_hole)
232523c35297Sanish {
232623c35297Sanish 	hole_t *nhole, *hole = addr_hole->next;
232723c35297Sanish 
232823c35297Sanish 	while (hole) {
232923c35297Sanish 		nhole = hole->next;
233023c35297Sanish 		kmem_free(hole, sizeof (hole_t));
233123c35297Sanish 		hole = nhole;
233223c35297Sanish 	}
233323c35297Sanish }
233423c35297Sanish 
233523c35297Sanish static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)233623c35297Sanish pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
233723c35297Sanish {
233823c35297Sanish 	uint64_t actual_hole_start, ostart, olen;
233923c35297Sanish 	hole_t	*hole = addr_hole, *thole, *nhole;
234023c35297Sanish 
234123c35297Sanish 	do {
234223c35297Sanish 		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
234323c35297Sanish 		if (((actual_hole_start - hole->start) + length) <= hole->len) {
234423c35297Sanish 			DEBUG3("hole found. start %llx, len %llx, req=0x%x\n",
234523c35297Sanish 			    hole->start, hole->len, length);
234623c35297Sanish 			ostart = hole->start;
234723c35297Sanish 			olen = hole->len;
234823c35297Sanish 			/* current hole parameters adjust */
234923c35297Sanish 			if ((actual_hole_start - hole->start) == 0) {
235023c35297Sanish 				hole->start += length;
235123c35297Sanish 				hole->len -= length;
235223c35297Sanish 				if (hole->start > *alast)
235323c35297Sanish 					*alast = hole->start;
235423c35297Sanish 			} else {
235523c35297Sanish 				hole->len = actual_hole_start - hole->start;
235623c35297Sanish 				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
235723c35297Sanish 				    KM_SLEEP);
235823c35297Sanish 				nhole->start = actual_hole_start + length;
235923c35297Sanish 				nhole->len = (ostart + olen) - nhole->start;
236023c35297Sanish 				nhole->next = NULL;
236123c35297Sanish 				thole = hole->next;
236223c35297Sanish 				hole->next = nhole;
236323c35297Sanish 				nhole->next = thole;
236423c35297Sanish 				if (nhole->start > *alast)
236523c35297Sanish 					*alast = nhole->start;
236623c35297Sanish 				DEBUG2("put new hole to %llx, %llx\n",
236723c35297Sanish 				    nhole->start, nhole->len);
236823c35297Sanish 			}
236923c35297Sanish 			DEBUG2("adjust current hole to %llx, %llx\n",
237023c35297Sanish 			    hole->start, hole->len);
237123c35297Sanish 			break;
237223c35297Sanish 		}
237323c35297Sanish 		actual_hole_start = 0;
237423c35297Sanish 		hole = hole->next;
237523c35297Sanish 	} while (hole);
237623c35297Sanish 
237723c35297Sanish 	DEBUG1("return hole at %llx\n", actual_hole_start);
237823c35297Sanish 	return (actual_hole_start);
237923c35297Sanish }
238023c35297Sanish 
238123c35297Sanish static void
pcicfg_get_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)238226947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
238323c35297Sanish {
238423c35297Sanish 	uint64_t new_mem;
238523c35297Sanish 
238623c35297Sanish 	/* See if there is a hole, that can hold this request. */
238723c35297Sanish 	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
238823c35297Sanish 	    length);
238923c35297Sanish 	if (new_mem) {	/* if non-zero, found a hole. */
239023c35297Sanish 		if (ans != NULL)
239123c35297Sanish 			*ans = new_mem;
239223c35297Sanish 	} else
239323c35297Sanish 		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
239423c35297Sanish 		    length, ddi_get_name(entry->dip));
239523c35297Sanish }
239623c35297Sanish 
239723c35297Sanish static void
pcicfg_get_io(pcicfg_phdl_t * entry,uint32_t length,uint32_t * ans)239823c35297Sanish pcicfg_get_io(pcicfg_phdl_t *entry,
239923c35297Sanish 	uint32_t length, uint32_t *ans)
240023c35297Sanish {
240123c35297Sanish 	uint32_t new_io;
240223c35297Sanish 	uint64_t io_last;
240323c35297Sanish 
240423c35297Sanish 	/*
240523c35297Sanish 	 * See if there is a hole, that can hold this request.
240623c35297Sanish 	 * Pass 64 bit parameters and then truncate to 32 bit.
240723c35297Sanish 	 */
240823c35297Sanish 	io_last = entry->io_last;
240923c35297Sanish 	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
241023c35297Sanish 	if (new_io) {	/* if non-zero, found a hole. */
241123c35297Sanish 		entry->io_last = (uint32_t)io_last;
241223c35297Sanish 		if (ans != NULL)
241323c35297Sanish 			*ans = new_io;
241423c35297Sanish 	} else
241523c35297Sanish 		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
241623c35297Sanish 		    length, ddi_get_name(entry->dip));
241723c35297Sanish }
241823c35297Sanish 
241923c35297Sanish static void
pcicfg_get_pf_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)242026947304SEvan Yan pcicfg_get_pf_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
242123c35297Sanish {
242223c35297Sanish 	uint64_t new_mem;
242323c35297Sanish 
242423c35297Sanish 	/* See if there is a hole, that can hold this request. */
242523c35297Sanish 	new_mem = pcicfg_alloc_hole(&entry->pf_mem_hole, &entry->pf_memory_last,
242623c35297Sanish 	    length);
242723c35297Sanish 	if (new_mem) {	/* if non-zero, found a hole. */
242823c35297Sanish 		if (ans != NULL)
242923c35297Sanish 			*ans = new_mem;
243023c35297Sanish 	} else
243123c35297Sanish 		cmn_err(CE_WARN, "No %u bytes PF memory window for %s\n",
243223c35297Sanish 		    length, ddi_get_name(entry->dip));
243323c35297Sanish }
243423c35297Sanish 
243523c35297Sanish static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)243623c35297Sanish pcicfg_sum_resources(dev_info_t *dip, void *hdl)
243723c35297Sanish {
243823c35297Sanish 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
243923c35297Sanish 	pci_regspec_t *pci_rp;
244023c35297Sanish 	int length;
244123c35297Sanish 	int rcount;
244223c35297Sanish 	int i;
244323c35297Sanish 	ndi_ra_request_t *pf_mem_request;
244423c35297Sanish 	ndi_ra_request_t *mem_request;
244523c35297Sanish 	ndi_ra_request_t *io_request;
244623c35297Sanish 	uint8_t header_type;
244723c35297Sanish 	ddi_acc_handle_t handle;
244823c35297Sanish 
244923c35297Sanish 	entry->error = PCICFG_SUCCESS;
245023c35297Sanish 
245123c35297Sanish 	pf_mem_request = &entry->pf_mem_req;
245223c35297Sanish 	mem_request = &entry->mem_req;
245323c35297Sanish 	io_request =  &entry->io_req;
245423c35297Sanish 
245523c35297Sanish 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
245623c35297Sanish 		DEBUG0("Failed to map config space!\n");
245723c35297Sanish 		entry->error = PCICFG_FAILURE;
245823c35297Sanish 		return (DDI_WALK_TERMINATE);
245923c35297Sanish 	}
246023c35297Sanish 
246123c35297Sanish 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
246223c35297Sanish 
246323c35297Sanish 	/*
246423c35297Sanish 	 * If its a bridge - just record the highest bus seen
246523c35297Sanish 	 */
246623c35297Sanish 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
246723c35297Sanish 
246823c35297Sanish 		if (entry->highest_bus < pci_config_get8(handle,
246923c35297Sanish 		    PCI_BCNF_SECBUS)) {
247023c35297Sanish 			entry->highest_bus =
247123c35297Sanish 			    pci_config_get8(handle, PCI_BCNF_SECBUS);
247223c35297Sanish 		}
247323c35297Sanish 		(void) pcicfg_config_teardown(&handle);
247423c35297Sanish 		entry->error = PCICFG_FAILURE;
247523c35297Sanish 		return (DDI_WALK_CONTINUE);
247623c35297Sanish 	} else {
247726947304SEvan Yan 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
247826947304SEvan Yan 		    "reg", (caddr_t)&pci_rp, &length) != DDI_PROP_SUCCESS) {
247923c35297Sanish 			/*
248023c35297Sanish 			 * If one node in (the subtree of nodes)
248123c35297Sanish 			 * doesn't have a "reg" property fail the
248223c35297Sanish 			 * allocation.
248323c35297Sanish 			 */
248423c35297Sanish 			entry->memory_len = 0;
248523c35297Sanish 			entry->io_len = 0;
248623c35297Sanish 			entry->pf_memory_len = 0;
248723c35297Sanish 			entry->error = PCICFG_FAILURE;
24881fb5b786Sprasad 			(void) pcicfg_config_teardown(&handle);
248923c35297Sanish 			return (DDI_WALK_TERMINATE);
249023c35297Sanish 		}
249123c35297Sanish 		/*
249223c35297Sanish 		 * For each "reg" property with a length, add that to the
249323c35297Sanish 		 * total memory (or I/O) to allocate.
249423c35297Sanish 		 */
249523c35297Sanish 		rcount = length / sizeof (pci_regspec_t);
249623c35297Sanish 
249723c35297Sanish 		for (i = 0; i < rcount; i++) {
249823c35297Sanish 
249923c35297Sanish 			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
250023c35297Sanish 
250123c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
250223c35297Sanish 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
250323c35297Sanish 					pf_mem_request->ra_len =
250423c35297Sanish 					    pci_rp[i].pci_size_low +
250526947304SEvan Yan 					    PCICFG_ROUND_UP(
250626947304SEvan Yan 					    pf_mem_request->ra_len,
250723c35297Sanish 					    pci_rp[i].pci_size_low);
250823c35297Sanish 					DEBUG1("ADDING 32 --->0x%x\n",
250923c35297Sanish 					    pci_rp[i].pci_size_low);
251023c35297Sanish 				} else {
251123c35297Sanish 					mem_request->ra_len =
251223c35297Sanish 					    pci_rp[i].pci_size_low +
251323c35297Sanish 					    PCICFG_ROUND_UP(mem_request->ra_len,
251423c35297Sanish 					    pci_rp[i].pci_size_low);
251523c35297Sanish 					DEBUG1("ADDING 32 --->0x%x\n",
251623c35297Sanish 					    pci_rp[i].pci_size_low);
251723c35297Sanish 				}
251823c35297Sanish 
251923c35297Sanish 				break;
252023c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
252123c35297Sanish 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
252223c35297Sanish 					pf_mem_request->ra_len =
252323c35297Sanish 					    pci_rp[i].pci_size_low +
252426947304SEvan Yan 					    PCICFG_ROUND_UP(
252526947304SEvan Yan 					    pf_mem_request->ra_len,
252623c35297Sanish 					    pci_rp[i].pci_size_low);
252723c35297Sanish 					DEBUG1("ADDING 64 --->0x%x\n",
252823c35297Sanish 					    pci_rp[i].pci_size_low);
252923c35297Sanish 				} else {
253023c35297Sanish 					mem_request->ra_len =
253123c35297Sanish 					    pci_rp[i].pci_size_low +
253223c35297Sanish 					    PCICFG_ROUND_UP(mem_request->ra_len,
253323c35297Sanish 					    pci_rp[i].pci_size_low);
253423c35297Sanish 					DEBUG1("ADDING 64 --->0x%x\n",
253523c35297Sanish 					    pci_rp[i].pci_size_low);
253623c35297Sanish 				}
253723c35297Sanish 
253823c35297Sanish 				break;
253923c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
254023c35297Sanish 				io_request->ra_len =
254123c35297Sanish 				    pci_rp[i].pci_size_low +
254223c35297Sanish 				    PCICFG_ROUND_UP(io_request->ra_len,
254323c35297Sanish 				    pci_rp[i].pci_size_low);
254423c35297Sanish 				DEBUG1("ADDING I/O --->0x%x\n",
254523c35297Sanish 				    pci_rp[i].pci_size_low);
254623c35297Sanish 				break;
254723c35297Sanish 			default:
254823c35297Sanish 				/* Config space register - not included */
254923c35297Sanish 				break;
255023c35297Sanish 			}
255123c35297Sanish 		}
255223c35297Sanish 
255323c35297Sanish 		/*
255423c35297Sanish 		 * free the memory allocated by ddi_getlongprop
255523c35297Sanish 		 */
255623c35297Sanish 		kmem_free(pci_rp, length);
255723c35297Sanish 
255823c35297Sanish 		/*
255923c35297Sanish 		 * continue the walk to the next sibling to sum memory
256023c35297Sanish 		 */
256123c35297Sanish 
256223c35297Sanish 		(void) pcicfg_config_teardown(&handle);
256323c35297Sanish 
256423c35297Sanish 		return (DDI_WALK_CONTINUE);
256523c35297Sanish 	}
256623c35297Sanish }
256723c35297Sanish 
256823c35297Sanish static int
pcicfg_free_bridge_resources(dev_info_t * dip)256923c35297Sanish pcicfg_free_bridge_resources(dev_info_t *dip)
257023c35297Sanish {
257123c35297Sanish 	ppb_ranges_t		*ranges;
257223c35297Sanish 	uint_t			*bus;
257323c35297Sanish 	int			k;
25741fb5b786Sprasad 	int			length = 0;
257523c35297Sanish 	int			i;
257623c35297Sanish 
257723c35297Sanish 
257826947304SEvan Yan 	if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
257926947304SEvan Yan 	    "ranges", (caddr_t)&ranges, &length)) != DDI_PROP_SUCCESS) {
258023c35297Sanish 		DEBUG0("Failed to read ranges property\n");
258123c35297Sanish 		if (ddi_get_child(dip)) {
258223c35297Sanish 			cmn_err(CE_WARN, "No ranges property found for %s",
258323c35297Sanish 			    ddi_get_name(dip));
258423c35297Sanish 			/*
258523c35297Sanish 			 * strictly speaking, we can check for children with
258623c35297Sanish 			 * assigned-addresses but for now it is better to
258723c35297Sanish 			 * be conservative and assume that if there are child
258823c35297Sanish 			 * nodes, then they do consume PCI memory or IO
258923c35297Sanish 			 * resources, Hence return failure.
259023c35297Sanish 			 */
259123c35297Sanish 			return (PCICFG_FAILURE);
259223c35297Sanish 		}
259323c35297Sanish 		length = 0;
259423c35297Sanish 	}
259523c35297Sanish 
259623c35297Sanish 	for (i = 0; i < length / sizeof (ppb_ranges_t); i++) {
259723c35297Sanish 		char *mem_type;
259823c35297Sanish 
259926947304SEvan Yan 		if (ranges[i].size_low != 0 || ranges[i].size_high != 0) {
260023c35297Sanish 			switch (ranges[i].parent_high & PCI_REG_ADDR_M) {
260123c35297Sanish 			case PCI_ADDR_IO:
260226947304SEvan Yan 				DEBUG2("Free I/O    base/length = "
260326947304SEvan Yan 				    "[0x%x]/[0x%x]\n", ranges[i].child_low,
260423c35297Sanish 				    ranges[i].size_low);
260523c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
260623c35297Sanish 				    (uint64_t)ranges[i].child_low,
260723c35297Sanish 				    (uint64_t)ranges[i].size_low,
260823c35297Sanish 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
260923c35297Sanish 				    != NDI_SUCCESS) {
261023c35297Sanish 					DEBUG0("Trouble freeing "
261123c35297Sanish 					    "PCI i/o space\n");
261223c35297Sanish 					kmem_free(ranges, length);
261323c35297Sanish 					return (PCICFG_FAILURE);
261423c35297Sanish 				}
261523c35297Sanish 				break;
261623c35297Sanish 			case PCI_ADDR_MEM32:
261723c35297Sanish 			case PCI_ADDR_MEM64:
261823c35297Sanish 				if (ranges[i].parent_high & PCI_REG_PF_M) {
261926947304SEvan Yan 					DEBUG3("Free PF Memory base/length = "
262026947304SEvan Yan 					    "[0x%x.0x%x]/[0x%x]\n",
262123c35297Sanish 					    ranges[i].child_mid,
262223c35297Sanish 					    ranges[i].child_low,
262326947304SEvan Yan 					    ranges[i].size_low);
262423c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
262523c35297Sanish 				} else {
262623c35297Sanish 					DEBUG3("Free Memory base/length"
262723c35297Sanish 					    " = [0x%x.0x%x]/[0x%x]\n",
262823c35297Sanish 					    ranges[i].child_mid,
262923c35297Sanish 					    ranges[i].child_low,
263023c35297Sanish 					    ranges[i].size_low)
263123c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
263223c35297Sanish 				}
263323c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
263426947304SEvan Yan 				    PCICFG_LADDR(ranges[i].child_low,
263523c35297Sanish 				    ranges[i].child_mid),
263623c35297Sanish 				    (uint64_t)ranges[i].size_low,
263726947304SEvan Yan 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
263823c35297Sanish 					DEBUG0("Trouble freeing "
263923c35297Sanish 					    "PCI memory space\n");
264023c35297Sanish 					kmem_free(ranges, length);
264123c35297Sanish 					return (PCICFG_FAILURE);
264223c35297Sanish 				}
264323c35297Sanish 				break;
264423c35297Sanish 			default:
264523c35297Sanish 				DEBUG0("Unknown memory space\n");
264623c35297Sanish 				break;
264723c35297Sanish 			}
264823c35297Sanish 		}
264923c35297Sanish 	}
265023c35297Sanish 
265123c35297Sanish 	if (length)
265223c35297Sanish 		kmem_free(ranges, length);
265323c35297Sanish 
265426947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
265526947304SEvan Yan 	    "bus-range", (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
265623c35297Sanish 		DEBUG0("Failed to read bus-range property\n");
265723c35297Sanish 		return (PCICFG_FAILURE);
265823c35297Sanish 	}
265923c35297Sanish 
266023c35297Sanish 	DEBUG2("Need to free bus [%d] range [%d]\n",
266123c35297Sanish 	    bus[0], bus[1] - bus[0] + 1);
266223c35297Sanish 
266326947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
266426947304SEvan Yan 	    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
266526947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
266623c35297Sanish 		DEBUG0("Failed to free a bus number\n");
26671fb5b786Sprasad 		kmem_free(bus, k);
266823c35297Sanish 		return (PCICFG_FAILURE);
266923c35297Sanish 	}
26701fb5b786Sprasad 
26711fb5b786Sprasad 	kmem_free(bus, k);
267223c35297Sanish 	return (PCICFG_SUCCESS);
267323c35297Sanish }
267423c35297Sanish 
267523c35297Sanish static int
pcicfg_free_device_resources(dev_info_t * dip)267623c35297Sanish pcicfg_free_device_resources(dev_info_t *dip)
267723c35297Sanish {
267823c35297Sanish 	pci_regspec_t *assigned;
267923c35297Sanish 
268023c35297Sanish 	int length;
268123c35297Sanish 	int acount;
268223c35297Sanish 	int i;
268323c35297Sanish 
268426947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
268526947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &length)
268626947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
268723c35297Sanish 		DEBUG0("Failed to read assigned-addresses property\n");
268823c35297Sanish 		return (PCICFG_FAILURE);
268923c35297Sanish 	}
269023c35297Sanish 
269123c35297Sanish 	/*
269223c35297Sanish 	 * For each "assigned-addresses" property entry with a length,
269323c35297Sanish 	 * call the memory allocation routines to return the
269423c35297Sanish 	 * resource.
269523c35297Sanish 	 */
269623c35297Sanish 	acount = length / sizeof (pci_regspec_t);
269723c35297Sanish 	for (i = 0; i < acount; i++) {
269823c35297Sanish 		char *mem_type;
269923c35297Sanish 
270023c35297Sanish 		/*
270123c35297Sanish 		 * Free the resource if the size of it is not zero.
270223c35297Sanish 		 */
270323c35297Sanish 		if ((assigned[i].pci_size_low != 0)||
270423c35297Sanish 		    (assigned[i].pci_size_hi != 0)) {
270523c35297Sanish 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
270623c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
270723c35297Sanish 				/*
270823c35297Sanish 				 * Check the assigned address for zero.
270923c35297Sanish 				 * (Workaround for Devconf (x86) bug to
271023c35297Sanish 				 * skip bogus entry for ROM base address
271123c35297Sanish 				 * register. If the assigned address is
271223c35297Sanish 				 * zero then ignore the entry
271323c35297Sanish 				 * (see bugid 4281306)).
271423c35297Sanish 				 */
271523c35297Sanish 				if (assigned[i].pci_phys_low == 0)
271623c35297Sanish 					break; /* ignore the entry */
271723c35297Sanish 
271823c35297Sanish 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
271923c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
272023c35297Sanish 				else
272123c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
272223c35297Sanish 
272323c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
272423c35297Sanish 				    (uint64_t)assigned[i].pci_phys_low,
272523c35297Sanish 				    (uint64_t)assigned[i].pci_size_low,
272623c35297Sanish 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
272723c35297Sanish 					DEBUG0("Trouble freeing "
272823c35297Sanish 					    "PCI memory space\n");
27291fb5b786Sprasad 					kmem_free(assigned, length);
273023c35297Sanish 					return (PCICFG_FAILURE);
273123c35297Sanish 				}
273223c35297Sanish 
273323c35297Sanish 				DEBUG4("Returned 0x%x of 32 bit %s space"
273423c35297Sanish 				    " @ 0x%x from register 0x%x\n",
273526947304SEvan Yan 				    assigned[i].pci_size_low, mem_type,
273623c35297Sanish 				    assigned[i].pci_phys_low,
273723c35297Sanish 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
273823c35297Sanish 
273923c35297Sanish 			break;
274023c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
274123c35297Sanish 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
274223c35297Sanish 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
274323c35297Sanish 				else
274423c35297Sanish 					mem_type = NDI_RA_TYPE_MEM;
274523c35297Sanish 
274623c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
274723c35297Sanish 				    PCICFG_LADDR(assigned[i].pci_phys_low,
274823c35297Sanish 				    assigned[i].pci_phys_mid),
274923c35297Sanish 				    (uint64_t)assigned[i].pci_size_low,
275023c35297Sanish 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
275123c35297Sanish 					DEBUG0("Trouble freeing "
275223c35297Sanish 					    "PCI memory space\n");
27531fb5b786Sprasad 					kmem_free(assigned, length);
275423c35297Sanish 					return (PCICFG_FAILURE);
275523c35297Sanish 				}
275623c35297Sanish 
275723c35297Sanish 				DEBUG5("Returned 0x%x of 64 bit %s space"
275823c35297Sanish 				    " @ 0x%x.0x%x from register 0x%x\n",
275923c35297Sanish 				    assigned[i].pci_size_low,
276026947304SEvan Yan 				    mem_type, assigned[i].pci_phys_mid,
276123c35297Sanish 				    assigned[i].pci_phys_low,
276223c35297Sanish 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
276323c35297Sanish 
276423c35297Sanish 			break;
276523c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
276623c35297Sanish 				if (ndi_ra_free(ddi_get_parent(dip),
276723c35297Sanish 				    (uint64_t)assigned[i].pci_phys_low,
276823c35297Sanish 				    (uint64_t)assigned[i].pci_size_low,
27691fb5b786Sprasad 				    NDI_RA_TYPE_IO, NDI_RA_PASS) !=
27701fb5b786Sprasad 				    NDI_SUCCESS) {
277123c35297Sanish 					DEBUG0("Trouble freeing "
277223c35297Sanish 					    "PCI IO space\n");
27731fb5b786Sprasad 					kmem_free(assigned, length);
277423c35297Sanish 					return (PCICFG_FAILURE);
277523c35297Sanish 				}
277626947304SEvan Yan 				DEBUG3("Returned 0x%x of IO space @ 0x%x from "
277726947304SEvan Yan 				    "register 0x%x\n", assigned[i].pci_size_low,
277823c35297Sanish 				    assigned[i].pci_phys_low,
277923c35297Sanish 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
278023c35297Sanish 			break;
278123c35297Sanish 			default:
278223c35297Sanish 				DEBUG0("Unknown register type\n");
278323c35297Sanish 				kmem_free(assigned, length);
278423c35297Sanish 				return (PCICFG_FAILURE);
278523c35297Sanish 			} /* switch */
278623c35297Sanish 		}
278723c35297Sanish 	}
278823c35297Sanish 	kmem_free(assigned, length);
278923c35297Sanish 	return (PCICFG_SUCCESS);
279023c35297Sanish }
279123c35297Sanish 
279223c35297Sanish static int
pcicfg_free_resources(dev_info_t * dip,pcicfg_flags_t flags)279326947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
279423c35297Sanish {
279523c35297Sanish 	ddi_acc_handle_t handle;
279623c35297Sanish 	uint8_t header_type;
279723c35297Sanish 
279823c35297Sanish 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
279923c35297Sanish 		DEBUG0("Failed to map config space!\n");
280023c35297Sanish 		return (PCICFG_FAILURE);
280123c35297Sanish 	}
280223c35297Sanish 
280323c35297Sanish 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
280423c35297Sanish 
280523c35297Sanish 	(void) pci_config_teardown(&handle);
280623c35297Sanish 
280723c35297Sanish 	/*
280823c35297Sanish 	 * A different algorithm is used for bridges and leaf devices.
280923c35297Sanish 	 */
281023c35297Sanish 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
281126947304SEvan Yan 		/*
281226947304SEvan Yan 		 * We only support readonly probing for leaf devices.
281326947304SEvan Yan 		 */
281426947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
281526947304SEvan Yan 			return (PCICFG_FAILURE);
281626947304SEvan Yan 
281723c35297Sanish 		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
281823c35297Sanish 			DEBUG0("Failed freeing up bridge resources\n");
281923c35297Sanish 			return (PCICFG_FAILURE);
282023c35297Sanish 		}
282123c35297Sanish 	} else {
282223c35297Sanish 		if (pcicfg_free_device_resources(dip) != PCICFG_SUCCESS) {
282323c35297Sanish 			DEBUG0("Failed freeing up device resources\n");
282423c35297Sanish 			return (PCICFG_FAILURE);
282523c35297Sanish 		}
282623c35297Sanish 	}
282723c35297Sanish 
282823c35297Sanish 	return (PCICFG_SUCCESS);
282923c35297Sanish }
283023c35297Sanish 
283123c35297Sanish #ifndef _DONT_USE_1275_GENERIC_NAMES
283223c35297Sanish static char *
pcicfg_get_class_name(uint32_t classcode)283323c35297Sanish pcicfg_get_class_name(uint32_t classcode)
283423c35297Sanish {
283523c35297Sanish 	struct pcicfg_name_entry *ptr;
283623c35297Sanish 
283723c35297Sanish 	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
283823c35297Sanish 		if (ptr->class_code == classcode) {
283923c35297Sanish 			return (ptr->name);
284023c35297Sanish 		}
284123c35297Sanish 	}
284223c35297Sanish 	return (NULL);
284323c35297Sanish }
284423c35297Sanish #endif /* _DONT_USE_1275_GENERIC_NAMES */
284523c35297Sanish 
284623c35297Sanish static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)284723c35297Sanish pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
284823c35297Sanish {
284923c35297Sanish 	struct pcicfg_find_ctrl ctrl;
285023c35297Sanish 	int count;
285123c35297Sanish 
285223c35297Sanish 	ctrl.device = device;
285323c35297Sanish 	ctrl.function = function;
285423c35297Sanish 	ctrl.dip = NULL;
285523c35297Sanish 
285623c35297Sanish 	ndi_devi_enter(dip, &count);
285723c35297Sanish 	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
285823c35297Sanish 	ndi_devi_exit(dip, count);
285923c35297Sanish 
286023c35297Sanish 	return (ctrl.dip);
286123c35297Sanish }
286223c35297Sanish 
286323c35297Sanish static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)286423c35297Sanish pcicfg_match_dev(dev_info_t *dip, void *hdl)
286523c35297Sanish {
286623c35297Sanish 	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
286723c35297Sanish 	pci_regspec_t *pci_rp;
286823c35297Sanish 	int length;
286923c35297Sanish 	int pci_dev;
287023c35297Sanish 	int pci_func;
287123c35297Sanish 
287226947304SEvan Yan 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
287326947304SEvan Yan 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
287423c35297Sanish 		ctrl->dip = NULL;
287523c35297Sanish 		return (DDI_WALK_TERMINATE);
287623c35297Sanish 	}
287723c35297Sanish 
287823c35297Sanish 	/* get the PCI device address info */
287923c35297Sanish 	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
288023c35297Sanish 	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
288123c35297Sanish 
288223c35297Sanish 	/*
288323c35297Sanish 	 * free the memory allocated by ddi_prop_lookup_int_array
288423c35297Sanish 	 */
288523c35297Sanish 	ddi_prop_free(pci_rp);
288623c35297Sanish 
288723c35297Sanish 
288823c35297Sanish 	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
288923c35297Sanish 		/* found the match for the specified device address */
289023c35297Sanish 		ctrl->dip = dip;
289123c35297Sanish 		return (DDI_WALK_TERMINATE);
289223c35297Sanish 	}
289323c35297Sanish 
289423c35297Sanish 	/*
289523c35297Sanish 	 * continue the walk to the next sibling to look for a match.
289623c35297Sanish 	 */
289723c35297Sanish 	return (DDI_WALK_PRUNECHILD);
289823c35297Sanish }
289923c35297Sanish 
290023c35297Sanish static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)290123c35297Sanish pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
290223c35297Sanish {
290323c35297Sanish 	int		alen;
290423c35297Sanish 	pci_regspec_t	*assigned;
290523c35297Sanish 	caddr_t		newreg;
290623c35297Sanish 	uint_t		status;
290723c35297Sanish 
290823c35297Sanish 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
290923c35297Sanish 	    "assigned-addresses", (caddr_t)&assigned, &alen);
291023c35297Sanish 	switch (status) {
291123c35297Sanish 		case DDI_PROP_SUCCESS:
291223c35297Sanish 		break;
291323c35297Sanish 		case DDI_PROP_NO_MEMORY:
291423c35297Sanish 			DEBUG0("no memory for assigned-addresses property\n");
291523c35297Sanish 			return (PCICFG_FAILURE);
291623c35297Sanish 		default:
291723c35297Sanish 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
291823c35297Sanish 			    "assigned-addresses", (int *)newone,
291923c35297Sanish 			    sizeof (*newone)/sizeof (int));
292023c35297Sanish 			return (PCICFG_SUCCESS);
292123c35297Sanish 	}
292223c35297Sanish 
292323c35297Sanish 	/*
292423c35297Sanish 	 * Allocate memory for the existing
292523c35297Sanish 	 * assigned-addresses(s) plus one and then
292623c35297Sanish 	 * build it.
292723c35297Sanish 	 */
292823c35297Sanish 
292923c35297Sanish 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
293023c35297Sanish 
293123c35297Sanish 	bcopy(assigned, newreg, alen);
293223c35297Sanish 	bcopy(newone, newreg + alen, sizeof (*newone));
293323c35297Sanish 
293423c35297Sanish 	/*
293523c35297Sanish 	 * Write out the new "assigned-addresses" spec
293623c35297Sanish 	 */
293723c35297Sanish 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
293823c35297Sanish 	    "assigned-addresses", (int *)newreg,
293923c35297Sanish 	    (alen + sizeof (*newone))/sizeof (int));
294023c35297Sanish 
294123c35297Sanish 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
294223c35297Sanish 	kmem_free(assigned, alen);
294323c35297Sanish 
294423c35297Sanish 	return (PCICFG_SUCCESS);
294523c35297Sanish }
294623c35297Sanish 
294723c35297Sanish static int
pcicfg_update_ranges_prop(dev_info_t * dip,ppb_ranges_t * addition)294823c35297Sanish pcicfg_update_ranges_prop(dev_info_t *dip, ppb_ranges_t *addition)
294923c35297Sanish {
295023c35297Sanish 	int		rlen;
295123c35297Sanish 	ppb_ranges_t	*ranges;
295223c35297Sanish 	caddr_t		newreg;
295323c35297Sanish 	uint_t		status;
295423c35297Sanish 
295526947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
295626947304SEvan Yan 	    "ranges", (caddr_t)&ranges, &rlen);
295723c35297Sanish 
295823c35297Sanish 
295923c35297Sanish 	switch (status) {
296023c35297Sanish 		case DDI_PROP_SUCCESS:
296123c35297Sanish 			break;
296223c35297Sanish 		case DDI_PROP_NO_MEMORY:
296323c35297Sanish 			DEBUG0("ranges present, but unable to get memory\n");
296423c35297Sanish 			return (PCICFG_FAILURE);
296523c35297Sanish 		default:
296623c35297Sanish 			DEBUG0("no ranges property - creating one\n");
296723c35297Sanish 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
296823c35297Sanish 			    dip, "ranges", (int *)addition,
296923c35297Sanish 			    sizeof (ppb_ranges_t)/sizeof (int))
297023c35297Sanish 			    != DDI_SUCCESS) {
297123c35297Sanish 				DEBUG0("Did'nt create ranges property\n");
297223c35297Sanish 				return (PCICFG_FAILURE);
297323c35297Sanish 			}
297423c35297Sanish 			return (PCICFG_SUCCESS);
297523c35297Sanish 	}
297623c35297Sanish 
297723c35297Sanish 	/*
297823c35297Sanish 	 * Allocate memory for the existing ranges plus one and then
297923c35297Sanish 	 * build it.
298023c35297Sanish 	 */
298123c35297Sanish 	newreg = kmem_zalloc(rlen+sizeof (ppb_ranges_t), KM_SLEEP);
298223c35297Sanish 
298323c35297Sanish 	bcopy(ranges, newreg, rlen);
298423c35297Sanish 	bcopy(addition, newreg + rlen, sizeof (ppb_ranges_t));
298523c35297Sanish 
298623c35297Sanish 	/*
298723c35297Sanish 	 * Write out the new "ranges" property
298823c35297Sanish 	 */
298926947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
299026947304SEvan Yan 	    (int *)newreg, (rlen + sizeof (ppb_ranges_t))/sizeof (int));
299123c35297Sanish 
299223c35297Sanish 	DEBUG1("Updating ranges property for %d entries",
299323c35297Sanish 	    rlen / sizeof (ppb_ranges_t) + 1);
299423c35297Sanish 
299523c35297Sanish 	kmem_free((caddr_t)newreg, rlen+sizeof (ppb_ranges_t));
299623c35297Sanish 
299723c35297Sanish 	kmem_free((caddr_t)ranges, rlen);
299823c35297Sanish 
299923c35297Sanish 	return (PCICFG_SUCCESS);
300023c35297Sanish }
300123c35297Sanish 
300223c35297Sanish static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)300323c35297Sanish pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
300423c35297Sanish {
300523c35297Sanish 	int		rlen;
300623c35297Sanish 	pci_regspec_t	*reg;
300723c35297Sanish 	caddr_t		newreg;
300823c35297Sanish 	uint32_t	hiword;
300923c35297Sanish 	pci_regspec_t	addition;
301023c35297Sanish 	uint32_t	size;
301123c35297Sanish 	uint_t		status;
301223c35297Sanish 
301323c35297Sanish 	status = ddi_getlongprop(DDI_DEV_T_ANY,
301423c35297Sanish 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
301523c35297Sanish 
301623c35297Sanish 	switch (status) {
301723c35297Sanish 		case DDI_PROP_SUCCESS:
301823c35297Sanish 		break;
301923c35297Sanish 		case DDI_PROP_NO_MEMORY:
302023c35297Sanish 			DEBUG0("reg present, but unable to get memory\n");
302123c35297Sanish 			return (PCICFG_FAILURE);
302223c35297Sanish 		default:
302323c35297Sanish 			DEBUG0("no reg property\n");
302423c35297Sanish 			return (PCICFG_FAILURE);
302523c35297Sanish 	}
302623c35297Sanish 
302723c35297Sanish 	/*
302823c35297Sanish 	 * Allocate memory for the existing reg(s) plus one and then
302923c35297Sanish 	 * build it.
303023c35297Sanish 	 */
303123c35297Sanish 	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
303223c35297Sanish 
303323c35297Sanish 	/*
303423c35297Sanish 	 * Build the regspec, then add it to the existing one(s)
303523c35297Sanish 	 */
303623c35297Sanish 
303723c35297Sanish 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
303823c35297Sanish 	    PCI_REG_DEV_G(reg->pci_phys_hi),
303923c35297Sanish 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
304023c35297Sanish 
304123c35297Sanish 	if (reg_offset == PCI_CONF_ROM) {
304223c35297Sanish 		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
304323c35297Sanish 		hiword |= PCI_ADDR_MEM32;
304423c35297Sanish 	} else {
304523c35297Sanish 		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
304623c35297Sanish 
304723c35297Sanish 		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
304823c35297Sanish 			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
304923c35297Sanish 				hiword |= PCI_ADDR_MEM32;
305023c35297Sanish 			} else if ((PCI_BASE_TYPE_M & regvalue)
305123c35297Sanish 			    == PCI_BASE_TYPE_ALL) {
305223c35297Sanish 				hiword |= PCI_ADDR_MEM64;
305323c35297Sanish 			}
305423c35297Sanish 			if (regvalue & PCI_BASE_PREF_M)
305523c35297Sanish 				hiword |= PCI_REG_PF_M;
305623c35297Sanish 		} else {
305723c35297Sanish 			hiword |= PCI_ADDR_IO;
305823c35297Sanish 		}
305923c35297Sanish 	}
306023c35297Sanish 
306123c35297Sanish 	addition.pci_phys_hi = hiword;
306223c35297Sanish 	addition.pci_phys_mid = 0;
306323c35297Sanish 	addition.pci_phys_low = 0;
306423c35297Sanish 	addition.pci_size_hi = 0;
306523c35297Sanish 	addition.pci_size_low = size;
306623c35297Sanish 
306723c35297Sanish 	bcopy(reg, newreg, rlen);
306823c35297Sanish 	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
306923c35297Sanish 
307023c35297Sanish 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
307123c35297Sanish 	/*
307223c35297Sanish 	 * Write out the new "reg" property
307323c35297Sanish 	 */
307426947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
307526947304SEvan Yan 	    (int *)newreg, (rlen + sizeof (pci_regspec_t))/sizeof (int));
307623c35297Sanish 
307723c35297Sanish 	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
307823c35297Sanish 	kmem_free((caddr_t)reg, rlen);
307923c35297Sanish 
308023c35297Sanish 	return (PCICFG_SUCCESS);
308123c35297Sanish }
308223c35297Sanish 
308326947304SEvan 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)308426947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
308526947304SEvan Yan     uint32_t base, uint32_t base_hi, uint_t reg_offset)
308626947304SEvan Yan {
308726947304SEvan Yan 	int		rlen;
308826947304SEvan Yan 	pci_regspec_t	*reg;
308926947304SEvan Yan 	uint32_t	hiword;
309026947304SEvan Yan 	pci_regspec_t	addition;
309126947304SEvan Yan 	uint_t		status;
309226947304SEvan Yan 
309326947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
309426947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
309526947304SEvan Yan 
309626947304SEvan Yan 	switch (status) {
309726947304SEvan Yan 		case DDI_PROP_SUCCESS:
309826947304SEvan Yan 		break;
309926947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
310026947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
310126947304SEvan Yan 			return (PCICFG_FAILURE);
310226947304SEvan Yan 		default:
310326947304SEvan Yan 			/*
310426947304SEvan Yan 			 * Since the config space "reg" entry should have been
310526947304SEvan Yan 			 * created, we expect a "reg" property already
310626947304SEvan Yan 			 * present here.
310726947304SEvan Yan 			 */
310826947304SEvan Yan 			DEBUG0("no reg property\n");
310926947304SEvan Yan 			return (PCICFG_FAILURE);
311026947304SEvan Yan 	}
311126947304SEvan Yan 
311226947304SEvan Yan 	/*
311326947304SEvan Yan 	 * Build the regspec, then add it to the existing one(s)
311426947304SEvan Yan 	 */
311526947304SEvan Yan 
311626947304SEvan Yan 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
311726947304SEvan Yan 	    PCI_REG_DEV_G(reg->pci_phys_hi),
311826947304SEvan Yan 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
311926947304SEvan Yan 
312026947304SEvan Yan 	hiword |= PCI_REG_REL_M;
312126947304SEvan Yan 
312226947304SEvan Yan 	if (reg_offset == PCI_CONF_ROM) {
312326947304SEvan Yan 		hiword |= PCI_ADDR_MEM32;
312426947304SEvan Yan 
312526947304SEvan Yan 		base = PCI_BASE_ROM_ADDR_M & base;
312626947304SEvan Yan 	} else {
312726947304SEvan Yan 		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
312826947304SEvan Yan 			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
312926947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
313026947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & base)
313126947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
313226947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
313326947304SEvan Yan 			}
313426947304SEvan Yan 			if (base & PCI_BASE_PREF_M)
313526947304SEvan Yan 				hiword |= PCI_REG_PF_M;
313626947304SEvan Yan 
313726947304SEvan Yan 			base = PCI_BASE_M_ADDR_M & base;
313826947304SEvan Yan 		} else {
313926947304SEvan Yan 			hiword |= PCI_ADDR_IO;
314026947304SEvan Yan 
314126947304SEvan Yan 			base = PCI_BASE_IO_ADDR_M & base;
314226947304SEvan Yan 			base_hi = 0;
314326947304SEvan Yan 		}
314426947304SEvan Yan 	}
314526947304SEvan Yan 
314626947304SEvan Yan 	addition.pci_phys_hi = hiword;
314726947304SEvan Yan 	addition.pci_phys_mid = base_hi;
314826947304SEvan Yan 	addition.pci_phys_low = base;
314926947304SEvan Yan 	addition.pci_size_hi = 0;
315026947304SEvan Yan 	addition.pci_size_low = size;
315126947304SEvan Yan 
315226947304SEvan Yan 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
315326947304SEvan Yan 
315426947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
315526947304SEvan Yan 
315626947304SEvan Yan 	return (pcicfg_update_assigned_prop(dip, &addition));
315726947304SEvan Yan }
315826947304SEvan Yan 
315923c35297Sanish static void
pcicfg_device_on(ddi_acc_handle_t config_handle)316023c35297Sanish pcicfg_device_on(ddi_acc_handle_t config_handle)
316123c35297Sanish {
316223c35297Sanish 	/*
316323c35297Sanish 	 * Enable memory, IO, and bus mastership
316423c35297Sanish 	 * XXX should we enable parity, SERR#,
316523c35297Sanish 	 * fast back-to-back, and addr. stepping?
316623c35297Sanish 	 */
316723c35297Sanish 	pci_config_put16(config_handle, PCI_CONF_COMM,
316823c35297Sanish 	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
316923c35297Sanish }
317023c35297Sanish 
317123c35297Sanish static void
pcicfg_device_off(ddi_acc_handle_t config_handle)317223c35297Sanish pcicfg_device_off(ddi_acc_handle_t config_handle)
317323c35297Sanish {
317423c35297Sanish 	/*
317523c35297Sanish 	 * Disable I/O and memory traffic through the bridge
317623c35297Sanish 	 */
317723c35297Sanish 	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
317823c35297Sanish }
317923c35297Sanish 
318023c35297Sanish /*
318123c35297Sanish  * Setup the basic 1275 properties based on information found in the config
318223c35297Sanish  * header of the PCI device
318323c35297Sanish  */
318423c35297Sanish static int
pcicfg_set_standard_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)318523c35297Sanish pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
318623c35297Sanish 	uint8_t pcie_dev)
318723c35297Sanish {
318849fbdd30SErwin T Tsaur 	int ret;
318949fbdd30SErwin T Tsaur 	uint16_t cap_id_loc, val;
319023c35297Sanish 	uint32_t wordval;
319123c35297Sanish 	uint8_t byteval;
319223c35297Sanish 
319323c35297Sanish 	/* These two exists only for non-bridges */
319426947304SEvan Yan 	if (((pci_config_get8(config_handle, PCI_CONF_HEADER) &
319526947304SEvan Yan 	    PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
319623c35297Sanish 		byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
319723c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
319823c35297Sanish 		    "min-grant", byteval)) != DDI_SUCCESS) {
319923c35297Sanish 			return (ret);
320023c35297Sanish 		}
320123c35297Sanish 
320223c35297Sanish 		byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
320323c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
320423c35297Sanish 		    "max-latency", byteval)) != DDI_SUCCESS) {
320523c35297Sanish 			return (ret);
320623c35297Sanish 		}
320723c35297Sanish 	}
320823c35297Sanish 
320923c35297Sanish 	/*
321023c35297Sanish 	 * These should always exist and have the value of the
321123c35297Sanish 	 * corresponding register value
321223c35297Sanish 	 */
321323c35297Sanish 	val = pci_config_get16(config_handle, PCI_CONF_VENID);
321423c35297Sanish 
321526947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id", val))
321626947304SEvan Yan 	    != DDI_SUCCESS) {
321723c35297Sanish 		return (ret);
321823c35297Sanish 	}
321923c35297Sanish 	val = pci_config_get16(config_handle, PCI_CONF_DEVID);
322026947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id", val))
322126947304SEvan Yan 	    != DDI_SUCCESS) {
322223c35297Sanish 		return (ret);
322323c35297Sanish 	}
322423c35297Sanish 	byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
322523c35297Sanish 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
322623c35297Sanish 	    "revision-id", byteval)) != DDI_SUCCESS) {
322723c35297Sanish 		return (ret);
322823c35297Sanish 	}
322923c35297Sanish 
323023c35297Sanish 	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
323123c35297Sanish 	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
323223c35297Sanish 
323323c35297Sanish 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
323423c35297Sanish 	    "class-code", wordval)) != DDI_SUCCESS) {
323523c35297Sanish 		return (ret);
323623c35297Sanish 	}
323726947304SEvan Yan 	val = (pci_config_get16(config_handle, PCI_CONF_STAT) &
323826947304SEvan Yan 	    PCI_STAT_DEVSELT);
323923c35297Sanish 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
324023c35297Sanish 	    "devsel-speed", val)) != DDI_SUCCESS) {
324123c35297Sanish 		return (ret);
324223c35297Sanish 	}
324323c35297Sanish 
324423c35297Sanish 	/*
324523c35297Sanish 	 * The next three are bits set in the status register.  The property is
324623c35297Sanish 	 * present (but with no value other than its own existence) if the bit
324723c35297Sanish 	 * is set, non-existent otherwise
324823c35297Sanish 	 */
324923c35297Sanish 	if ((!pcie_dev) &&
325026947304SEvan Yan 	    (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_FBBC)) {
325123c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
325223c35297Sanish 		    "fast-back-to-back", 0)) != DDI_SUCCESS) {
325323c35297Sanish 			return (ret);
325423c35297Sanish 		}
325523c35297Sanish 	}
325623c35297Sanish 	if ((!pcie_dev) &&
325726947304SEvan Yan 	    (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_66MHZ)) {
325823c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
325923c35297Sanish 		    "66mhz-capable", 0)) != DDI_SUCCESS) {
326023c35297Sanish 			return (ret);
326123c35297Sanish 		}
326223c35297Sanish 	}
326323c35297Sanish 	if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
326423c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
326523c35297Sanish 		    "udf-supported", 0)) != DDI_SUCCESS) {
326623c35297Sanish 			return (ret);
326723c35297Sanish 		}
326823c35297Sanish 	}
326923c35297Sanish 
327023c35297Sanish 	/*
327123c35297Sanish 	 * These next three are optional and are not present
327223c35297Sanish 	 * if the corresponding register is zero.  If the value
327323c35297Sanish 	 * is non-zero then the property exists with the value
327423c35297Sanish 	 * of the register.
327523c35297Sanish 	 */
327626947304SEvan Yan 	if ((val = pci_config_get16(config_handle, PCI_CONF_SUBVENID)) != 0) {
327723c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
327823c35297Sanish 		    "subsystem-vendor-id", val)) != DDI_SUCCESS) {
327923c35297Sanish 			return (ret);
328023c35297Sanish 		}
328123c35297Sanish 	}
328226947304SEvan Yan 	if ((val = pci_config_get16(config_handle, PCI_CONF_SUBSYSID)) != 0) {
328323c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
328423c35297Sanish 		    "subsystem-id", val)) != DDI_SUCCESS) {
328523c35297Sanish 			return (ret);
328623c35297Sanish 		}
328723c35297Sanish 	}
328826947304SEvan Yan 	if ((val = pci_config_get16(config_handle, PCI_CONF_CACHE_LINESZ))
328926947304SEvan Yan 	    != 0) {
329023c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
329123c35297Sanish 		    "cache-line-size", val)) != DDI_SUCCESS) {
329223c35297Sanish 			return (ret);
329323c35297Sanish 		}
329423c35297Sanish 	}
329523c35297Sanish 
329623c35297Sanish 	/*
329723c35297Sanish 	 * If the Interrupt Pin register is non-zero then the
329823c35297Sanish 	 * interrupts property exists
329923c35297Sanish 	 */
330023c35297Sanish 	if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
330123c35297Sanish 		/*
330223c35297Sanish 		 * If interrupt pin is non-zero,
330323c35297Sanish 		 * record the interrupt line used
330423c35297Sanish 		 */
330523c35297Sanish 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
330623c35297Sanish 		    "interrupts", byteval)) != DDI_SUCCESS) {
330723c35297Sanish 			return (ret);
330823c35297Sanish 		}
330923c35297Sanish 	}
331049fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
331149fbdd30SErwin T Tsaur 	if (pcie_dev && cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
331226947304SEvan Yan 		val = pci_config_get16(config_handle, cap_id_loc + PCIE_PCIECAP)
331326947304SEvan Yan 		    & PCIE_PCIECAP_SLOT_IMPL;
331423c35297Sanish 		/* if slot implemented, get physical slot number */
331523c35297Sanish 		if (val) {
331623c35297Sanish 			wordval = pci_config_get32(config_handle, cap_id_loc +
331723c35297Sanish 			    PCIE_SLOTCAP);
331823c35297Sanish 			/* create the property only if slotnum set correctly? */
331923c35297Sanish 			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
332023c35297Sanish 			    "physical-slot#", PCIE_SLOTCAP_PHY_SLOT_NUM(
332123c35297Sanish 			    wordval))) != DDI_SUCCESS) {
332223c35297Sanish 				return (ret);
332323c35297Sanish 			}
332423c35297Sanish 		}
332523c35297Sanish 	}
332623c35297Sanish 
332723c35297Sanish 	return (PCICFG_SUCCESS);
332823c35297Sanish }
332923c35297Sanish 
333023c35297Sanish static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type)333123c35297Sanish pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type)
333223c35297Sanish {
333323c35297Sanish 	int ret;
333423c35297Sanish 	char device_type[8];
333523c35297Sanish 
333623c35297Sanish 	if (pcie_device_type)
333723c35297Sanish 		(void) strcpy(device_type, "pciex");
333823c35297Sanish 	else
333923c35297Sanish 		(void) strcpy(device_type, "pci");
334023c35297Sanish 
334123c35297Sanish 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
334223c35297Sanish 	    "device_type", device_type)) != DDI_SUCCESS) {
334323c35297Sanish 		return (ret);
334423c35297Sanish 	}
334523c35297Sanish 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
334623c35297Sanish 	    "#address-cells", 3)) != DDI_SUCCESS) {
334723c35297Sanish 		return (ret);
334823c35297Sanish 	}
334926947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 2))
335026947304SEvan Yan 	    != DDI_SUCCESS) {
335123c35297Sanish 		return (ret);
335223c35297Sanish 	}
335323c35297Sanish 	return (PCICFG_SUCCESS);
335423c35297Sanish }
335523c35297Sanish 
335623c35297Sanish static int
pcicfg_set_childnode_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)335723c35297Sanish pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
335823c35297Sanish 		uint8_t pcie_dev)
335923c35297Sanish {
336023c35297Sanish 
336123c35297Sanish 	int		ret;
336223c35297Sanish 	char		*name;
336323c35297Sanish 	char		buffer[64], pprefix[8], nprefix[8];
336423c35297Sanish 	uint16_t	classcode;
336523c35297Sanish 	uint8_t		revid, pif, pclass, psubclass;
336623c35297Sanish 	char		*compat[24];
336723c35297Sanish 	int		i;
336823c35297Sanish 	int		n;
336923c35297Sanish 	uint16_t		sub_vid, sub_sid, vid, did;
337023c35297Sanish 	/* set the property prefix based on the device type */
337123c35297Sanish 	if (pcie_dev) {
337223c35297Sanish 		(void) sprintf(pprefix, "pciex");
337323c35297Sanish 	} else
337423c35297Sanish 		(void) sprintf(pprefix, "pci");
337523c35297Sanish 
337623c35297Sanish 	/* set the prefix right for name property */
337723c35297Sanish 	/* x86 platforms need to go with pci for upgrade purposes */
337823c35297Sanish 	(void) sprintf(nprefix, "pci");
337923c35297Sanish 
338023c35297Sanish 	/*
338123c35297Sanish 	 * NOTE: These are for both a child and PCI-PCI bridge node
338223c35297Sanish 	 */
338326947304SEvan Yan 	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
338423c35297Sanish 	sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
338526947304SEvan Yan 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
338623c35297Sanish 	did = pci_config_get16(config_handle, PCI_CONF_DEVID);
338723c35297Sanish 	revid = pci_config_get8(config_handle, PCI_CONF_REVID);
338823c35297Sanish 	pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
338923c35297Sanish 	classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
339023c35297Sanish 	pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
339123c35297Sanish 	psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
339223c35297Sanish 
3393b2e8ece4Sprasad 	if (!sub_vid)
339423c35297Sanish 		(void) sprintf(buffer, "%s%x,%x", nprefix, vid, did);
339523c35297Sanish 	else
339623c35297Sanish 		(void) sprintf(buffer, "%s%x,%x", nprefix, sub_vid, sub_sid);
339723c35297Sanish 
339823c35297Sanish 	/*
339923c35297Sanish 	 * In some environments, trying to use "generic" 1275 names is
340023c35297Sanish 	 * not the convention.  In those cases use the name as created
340123c35297Sanish 	 * above.  In all the rest of the cases, check to see if there
340223c35297Sanish 	 * is a generic name first.
340323c35297Sanish 	 */
340423c35297Sanish #ifdef _DONT_USE_1275_GENERIC_NAMES
340523c35297Sanish 	name = buffer;
340623c35297Sanish #else
340723c35297Sanish 	if ((name = pcicfg_get_class_name(classcode)) == NULL) {
340823c35297Sanish 		/*
340923c35297Sanish 		 * Set name to the above fabricated name
341023c35297Sanish 		 */
341123c35297Sanish 		name = buffer;
341223c35297Sanish 	}
341323c35297Sanish #endif
341423c35297Sanish 
341523c35297Sanish 	/*
341623c35297Sanish 	 * The node name field needs to be filled in with the name
341723c35297Sanish 	 */
341823c35297Sanish 	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
341923c35297Sanish 		DEBUG0("Failed to set nodename for node\n");
342023c35297Sanish 		return (PCICFG_FAILURE);
342123c35297Sanish 	}
342223c35297Sanish 
342323c35297Sanish 	/*
342423c35297Sanish 	 * Create the compatible property as an array of pointers
342523c35297Sanish 	 * to strings.  Start with the buffer created above.
342623c35297Sanish 	 */
342723c35297Sanish 	n = 0;
342823c35297Sanish 
342923c35297Sanish 	/*
343023c35297Sanish 	 * Setup 'compatible' as per the PCI2.1 bindings document.
343123c35297Sanish 	 *	pci[ex]VVVV,DDDD.SSSS.ssss.RR
343223c35297Sanish 	 *	pci[ex]VVVV,DDDD.SSSS.ssss
343323c35297Sanish 	 *	pciSSSS.ssss  -> not created for PCIe as per PCIe bindings
343423c35297Sanish 	 *	pci[ex]VVVV,DDDD.RR
343523c35297Sanish 	 *	pci[ex]VVVV,DDDD
343623c35297Sanish 	 *	pci[ex]class,CCSSPP
343723c35297Sanish 	 *	pci[ex]class,CCSS
343823c35297Sanish 	 * Add legacy entries for compatibility with legacy devices and OS
343923c35297Sanish 	 * for x86.
344023c35297Sanish 	 *	pciVVVV,DDDD.SSSS.ssss.RR
344123c35297Sanish 	 *	pciVVVV,DDDD.SSSS.ssss
344223c35297Sanish 	 *	pciSSSS.ssss
344323c35297Sanish 	 *	pciVVVV,DDDD.RR
344423c35297Sanish 	 *	pciVVVV,DDDD
344523c35297Sanish 	 *	pciclass,CCSSPP
344623c35297Sanish 	 *	pciclass,CCSS
344723c35297Sanish 	 */
344823c35297Sanish 
344923c35297Sanish 	do {
3450b2e8ece4Sprasad 		if (sub_vid) {
345123c35297Sanish 			/* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
345226947304SEvan Yan 			(void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix, vid,
345326947304SEvan Yan 			    did, sub_vid, sub_sid, revid);
345423c35297Sanish 			compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
345523c35297Sanish 			(void) strcpy(compat[n++], buffer);
345623c35297Sanish 
345723c35297Sanish 			/* pci[ex]VVVV,DDDD.SSSS.ssss */
345826947304SEvan Yan 			(void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid,
345926947304SEvan Yan 			    did, sub_vid, sub_sid);
346023c35297Sanish 			compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
346123c35297Sanish 			(void) strcpy(compat[n++], buffer);
346223c35297Sanish 
3463b2e8ece4Sprasad 			/* pciSSSS.ssss  -> not created for PCIe as per PCIe */
3464b2e8ece4Sprasad 			/* binding to IEEE 1275 spec.			 */
346523c35297Sanish 			if (!pcie_dev && pcicfg_do_legacy_props) {
346626947304SEvan Yan 				(void) sprintf(buffer, "pci%x,%x", sub_vid,
346726947304SEvan Yan 				    sub_sid);
346826947304SEvan Yan 				compat[n] = kmem_alloc(strlen(buffer) + 1,
346926947304SEvan Yan 				    KM_SLEEP);
347023c35297Sanish 				(void) strcpy(compat[n++], buffer);
347123c35297Sanish 			}
3472b2e8ece4Sprasad 		}
347323c35297Sanish 
347423c35297Sanish 		/* pci[ex]VVVV,DDDD.RR */
347523c35297Sanish 		(void) sprintf(buffer, "%s%x,%x.%x", pprefix,  vid, did, revid);
347623c35297Sanish 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
347723c35297Sanish 		(void) strcpy(compat[n++], buffer);
347823c35297Sanish 
347923c35297Sanish 		/* pci[ex]VVVV,DDDD */
348023c35297Sanish 		(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
348123c35297Sanish 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
348223c35297Sanish 		(void) strcpy(compat[n++], buffer);
348323c35297Sanish 
348423c35297Sanish 		/* pci[ex]class,CCSSPP */
348526947304SEvan Yan 		(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix, pclass,
348626947304SEvan Yan 		    psubclass, pif);
348723c35297Sanish 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
348823c35297Sanish 		(void) strcpy(compat[n++], buffer);
348923c35297Sanish 
349023c35297Sanish 		/* pci[ex]class,CCSS */
349123c35297Sanish 		(void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
349223c35297Sanish 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
349323c35297Sanish 		(void) strcpy(compat[n++], buffer);
349423c35297Sanish 
349523c35297Sanish 		if (!pcie_dev)
349623c35297Sanish 			break;
349723c35297Sanish 
349823c35297Sanish 		/* also add compatible names using "pci" prefix */
349923c35297Sanish 		(void) sprintf(pprefix, "pci");
350023c35297Sanish 		pcie_dev = 0;
350123c35297Sanish 
350223c35297Sanish 	} while (pcicfg_do_legacy_props);
350323c35297Sanish 
350426947304SEvan Yan 	ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
350526947304SEvan Yan 	    (char **)compat, n);
350623c35297Sanish 
350723c35297Sanish 	for (i = 0; i < n; i++) {
350823c35297Sanish 		kmem_free(compat[i], strlen(compat[i]) + 1);
350923c35297Sanish 	}
351023c35297Sanish 
35111fb5b786Sprasad 	return (ret);
351223c35297Sanish }
351323c35297Sanish 
351423c35297Sanish /*
351523c35297Sanish  * Program the bus numbers into the bridge
351623c35297Sanish  */
351723c35297Sanish static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,uint_t primary,uint_t secondary,uint_t subordinate)351823c35297Sanish pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
351923c35297Sanish uint_t primary, uint_t secondary, uint_t subordinate)
352023c35297Sanish {
352123c35297Sanish 	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
352223c35297Sanish 	    subordinate);
352323c35297Sanish 	/*
352423c35297Sanish 	 * Primary bus#
352523c35297Sanish 	 */
352623c35297Sanish 	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
352723c35297Sanish 
352823c35297Sanish 	/*
352923c35297Sanish 	 * Secondary bus#
353023c35297Sanish 	 */
353123c35297Sanish 	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
353223c35297Sanish 
353323c35297Sanish 	/*
353423c35297Sanish 	 * Set the subordinate bus number to ff in order to pass through any
353523c35297Sanish 	 * type 1 cycle with a bus number higher than the secondary bus#
353623c35297Sanish 	 */
353723c35297Sanish 	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
353823c35297Sanish }
353923c35297Sanish 
354023c35297Sanish /*
354123c35297Sanish  * Put bridge registers into initial state
354223c35297Sanish  */
354323c35297Sanish static void
pcicfg_setup_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)354423c35297Sanish pcicfg_setup_bridge(pcicfg_phdl_t *entry,
354523c35297Sanish 	ddi_acc_handle_t handle)
354623c35297Sanish {
354723c35297Sanish 	/*
354823c35297Sanish 	 * The highest bus seen during probing is the max-subordinate bus
354923c35297Sanish 	 */
355023c35297Sanish 	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
355123c35297Sanish 
355223c35297Sanish 	/*
355323c35297Sanish 	 * Reset the secondary bus
355423c35297Sanish 	 */
355523c35297Sanish 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
355623c35297Sanish 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
355723c35297Sanish 	drv_usecwait(1000);
355823c35297Sanish 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
355923c35297Sanish 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
356023c35297Sanish 	drv_usecwait(1000);
356123c35297Sanish 
356223c35297Sanish 	/*
356323c35297Sanish 	 * Program the memory base register with the
356423c35297Sanish 	 * start of the memory range
356523c35297Sanish 	 */
356623c35297Sanish 	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
356723c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
356823c35297Sanish 
356923c35297Sanish 	/*
357023c35297Sanish 	 * Program the I/O base register with the start of the I/O range
357123c35297Sanish 	 */
357223c35297Sanish 	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
357323c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
357423c35297Sanish 	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
357523c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
357623c35297Sanish 
357723c35297Sanish 	/*
357823c35297Sanish 	 * Program the PF memory base register with the start of
357923c35297Sanish 	 * PF memory range
358023c35297Sanish 	 */
358123c35297Sanish 	pci_config_put16(handle, PCI_BCNF_PF_BASE_LOW,
358223c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
358323c35297Sanish 	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH,
358423c35297Sanish 	    PCICFG_HIADDR(entry->pf_memory_last));
358523c35297Sanish 
358623c35297Sanish 	/*
358723c35297Sanish 	 * Clear status bits
358823c35297Sanish 	 */
358923c35297Sanish 	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
359023c35297Sanish 
359123c35297Sanish 	/*
359223c35297Sanish 	 * Needs to be set to this value
359323c35297Sanish 	 */
359423c35297Sanish 	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
359523c35297Sanish 
359623c35297Sanish 	/*
359723c35297Sanish 	 * XXX - may be delay should be used since noone configures
359823c35297Sanish 	 * devices in the interrupt context
359923c35297Sanish 	 */
360023c35297Sanish 	drv_usecwait(pcicfg_sec_reset_delay);	/* 1 sec wait */
360123c35297Sanish }
360223c35297Sanish 
360323c35297Sanish static void
pcicfg_update_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)360423c35297Sanish pcicfg_update_bridge(pcicfg_phdl_t *entry,
360523c35297Sanish 	ddi_acc_handle_t handle)
360623c35297Sanish {
360723c35297Sanish 	uint_t length;
360823c35297Sanish 
360923c35297Sanish 	/*
361023c35297Sanish 	 * Program the memory limit register with the end of the memory range
361123c35297Sanish 	 */
361223c35297Sanish 
361323c35297Sanish 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
361426947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN));
361523c35297Sanish 
361623c35297Sanish 	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
361723c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
361826947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN))));
361923c35297Sanish 	/*
362023c35297Sanish 	 * Since this is a bridge, the rest of this range will
362123c35297Sanish 	 * be responded to by the bridge.  We have to round up
362223c35297Sanish 	 * so no other device claims it.
362323c35297Sanish 	 */
362426947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN)
362526947304SEvan Yan 	    - entry->memory_last)) > 0) {
362623c35297Sanish 		(void) pcicfg_get_mem(entry, length, NULL);
362726947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (mem)\n", length);
362823c35297Sanish 	}
362923c35297Sanish 
363023c35297Sanish 	/*
363123c35297Sanish 	 * Program the PF memory limit register with the end of the memory range
363223c35297Sanish 	 */
363323c35297Sanish 
363423c35297Sanish 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
363526947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN));
363623c35297Sanish 
363723c35297Sanish 	pci_config_put16(handle, PCI_BCNF_PF_LIMIT_LOW,
363826947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(
363926947304SEvan Yan 	    entry->pf_memory_last, PCICFG_MEMGRAN))));
364026947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, PCICFG_HIADDR(
364126947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN)));
364226947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->pf_memory_last, PCICFG_MEMGRAN)
364326947304SEvan Yan 	    - entry->pf_memory_last)) > 0) {
364423c35297Sanish 		(void) pcicfg_get_pf_mem(entry, length, NULL);
364526947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (PF mem)\n",
364626947304SEvan Yan 		    length);
364723c35297Sanish 	}
364823c35297Sanish 
364923c35297Sanish 	/*
365023c35297Sanish 	 * Program the I/O limit register with the end of the I/O range
365123c35297Sanish 	 */
365223c35297Sanish 	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
365323c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(
365426947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN)))));
365523c35297Sanish 
365626947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, PCICFG_HIWORD(
365726947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN))));
365823c35297Sanish 
365923c35297Sanish 	/*
366023c35297Sanish 	 * Same as above for I/O space. Since this is a
366123c35297Sanish 	 * bridge, the rest of this range will be responded
366223c35297Sanish 	 * to by the bridge.  We have to round up so no
366323c35297Sanish 	 * other device claims it.
366423c35297Sanish 	 */
366526947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN)
366626947304SEvan Yan 	    - entry->io_last)) > 0) {
366723c35297Sanish 		(void) pcicfg_get_io(entry, length, NULL);
366826947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (I/O)\n", length);
366923c35297Sanish 	}
367023c35297Sanish }
367123c35297Sanish 
367223c35297Sanish 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)367326947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
3674c0da6274SZhi-Jun Robin Fu     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
367523c35297Sanish {
367623c35297Sanish 	dev_info_t		*new_child;
367723c35297Sanish 	ddi_acc_handle_t	config_handle;
367823c35297Sanish 	uint8_t			header_type, pcie_dev = 0;
36795af4ae46Sjveta 	int			ret = PCICFG_FAILURE;
368023c35297Sanish 
368123c35297Sanish 	/*
368223c35297Sanish 	 * This node will be put immediately below
368323c35297Sanish 	 * "parent". Allocate a blank device node.  It will either
368423c35297Sanish 	 * be filled in or freed up based on further probing.
368523c35297Sanish 	 */
368623c35297Sanish 
368723c35297Sanish 	ndi_devi_alloc_sleep(parent, DEVI_PSEUDO_NEXNAME,
368823c35297Sanish 	    (pnode_t)DEVI_SID_NODEID, &new_child);
368923c35297Sanish 
369026947304SEvan Yan 	if (pcicfg_add_config_reg(new_child, bus, device, func)
369126947304SEvan Yan 	    != DDI_SUCCESS) {
369226947304SEvan Yan 		DEBUG0("pcicfg_probe_children():Failed to add candidate REG\n");
369323c35297Sanish 		goto failedconfig;
369423c35297Sanish 	}
369523c35297Sanish 
369623c35297Sanish 	if ((ret = pcicfg_config_setup(new_child, &config_handle))
369723c35297Sanish 	    != PCICFG_SUCCESS) {
369823c35297Sanish 		if (ret == PCICFG_NODEVICE) {
369923c35297Sanish 			(void) ndi_devi_free(new_child);
370023c35297Sanish 			return (ret);
370123c35297Sanish 		}
370223c35297Sanish 		DEBUG0("pcicfg_probe_children():"
370323c35297Sanish 		"Failed to setup config space\n");
370423c35297Sanish 		goto failedconfig;
370523c35297Sanish 	}
370623c35297Sanish 
3707c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3708c0da6274SZhi-Jun Robin Fu 		(void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
3709c0da6274SZhi-Jun Robin Fu 		    PCIE_BUS_INITIAL);
3710c0da6274SZhi-Jun Robin Fu 
371123c35297Sanish 	/*
371223c35297Sanish 	 * As soon as we have access to config space,
371323c35297Sanish 	 * turn off device. It will get turned on
371423c35297Sanish 	 * later (after memory is assigned).
371523c35297Sanish 	 */
371623c35297Sanish 	(void) pcicfg_device_off(config_handle);
371723c35297Sanish 
371823c35297Sanish 	/* check if we are PCIe device */
371923c35297Sanish 	if (pcicfg_pcie_dev(new_child, config_handle) == DDI_SUCCESS) {
372023c35297Sanish 		DEBUG0("PCIe device detected\n");
372123c35297Sanish 		pcie_dev = 1;
372223c35297Sanish 	}
372323c35297Sanish 
372423c35297Sanish 	/*
372523c35297Sanish 	 * Set 1275 properties common to all devices
372623c35297Sanish 	 */
372726947304SEvan Yan 	if (pcicfg_set_standard_props(new_child, config_handle, pcie_dev)
372826947304SEvan Yan 	    != PCICFG_SUCCESS) {
372923c35297Sanish 		DEBUG0("Failed to set standard properties\n");
373023c35297Sanish 		goto failedchild;
373123c35297Sanish 	}
373223c35297Sanish 
373323c35297Sanish 	/*
373423c35297Sanish 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
373523c35297Sanish 	 */
373626947304SEvan Yan 	if (pcicfg_set_childnode_props(new_child, config_handle, pcie_dev)
373726947304SEvan Yan 	    != PCICFG_SUCCESS) {
373823c35297Sanish 		goto failedchild;
373923c35297Sanish 	}
374023c35297Sanish 
374123c35297Sanish 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
374223c35297Sanish 
374323c35297Sanish 	/*
374423c35297Sanish 	 * If this is not a multi-function card only probe function zero.
374523c35297Sanish 	 */
374623c35297Sanish 	if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
374723c35297Sanish 
3748c0da6274SZhi-Jun Robin Fu 		ret = PCICFG_NODEVICE;
3749c0da6274SZhi-Jun Robin Fu 		goto failedchild;
375023c35297Sanish 	}
375123c35297Sanish 
375223c35297Sanish 	/*
375323c35297Sanish 	 * Attach the child to its parent
375423c35297Sanish 	 */
375523c35297Sanish 	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
375623c35297Sanish 
37573a634bfcSVikram Hegde 	DEVI_SET_PCI(new_child);
37583a634bfcSVikram Hegde 
375923c35297Sanish 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
376023c35297Sanish 
376126947304SEvan Yan 		DEBUG3("--Bridge found bus [0x%x] device[0x%x] func [0x%x]\n",
376226947304SEvan Yan 		    bus, device, func);
376326947304SEvan Yan 
376426947304SEvan Yan 		/* Only support read-only probe for leaf device */
376526947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
376626947304SEvan Yan 			goto failedchild;
376723c35297Sanish 
37685af4ae46Sjveta 		ret = pcicfg_probe_bridge(new_child, config_handle, bus,
3769c0da6274SZhi-Jun Robin Fu 		    highest_bus, is_pcie);
37705af4ae46Sjveta 		if (ret != PCICFG_SUCCESS) {
377123c35297Sanish 			(void) pcicfg_free_bridge_resources(new_child);
377223c35297Sanish 			goto failedchild;
377323c35297Sanish 		}
377423c35297Sanish 
377523c35297Sanish 	} else {
377623c35297Sanish 
377723c35297Sanish 		DEBUG3("--Leaf device found bus [0x%x] device"
377826947304SEvan Yan 		    "[0x%x] func [0x%x]\n", bus, device, func);
377926947304SEvan Yan 
378026947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY) {
378126947304SEvan Yan 			/*
378226947304SEvan Yan 			 * with read-only probe, don't do any resource
378326947304SEvan Yan 			 * allocation, just read the BARs and update props.
378426947304SEvan Yan 			 */
378526947304SEvan Yan 			ret = pcicfg_populate_props_from_bar(new_child,
378626947304SEvan Yan 			    config_handle);
378726947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
378826947304SEvan Yan 				goto failedchild;
378926947304SEvan Yan 
379026947304SEvan Yan 			/*
379126947304SEvan Yan 			 * now allocate the resources, just remove the
379226947304SEvan Yan 			 * resources from the parent busra pool.
379326947304SEvan Yan 			 */
379426947304SEvan Yan 			ret = pcicfg_device_assign_readonly(new_child);
379526947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
379626947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child);
379726947304SEvan Yan 				goto failedchild;
379826947304SEvan Yan 			}
379926947304SEvan Yan 
380026947304SEvan Yan 		} else {
380126947304SEvan Yan 			/*
380226947304SEvan Yan 			 * update "reg" property by sizing the BARs.
380326947304SEvan Yan 			 */
380426947304SEvan Yan 			ret = pcicfg_populate_reg_props(new_child,
380526947304SEvan Yan 			    config_handle);
380626947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
380726947304SEvan Yan 				goto failedchild;
380826947304SEvan Yan 
380926947304SEvan Yan 			/* now allocate & program the resources */
381026947304SEvan Yan 			ret = pcicfg_device_assign(new_child);
381126947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
381226947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child);
381326947304SEvan Yan 				goto failedchild;
381426947304SEvan Yan 			}
381526947304SEvan Yan 		}
381626947304SEvan Yan 
381726947304SEvan Yan 		(void) ndi_devi_bind_driver(new_child, 0);
381826947304SEvan Yan 	}
381926947304SEvan Yan 
382026947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
382126947304SEvan Yan 
3822c0da6274SZhi-Jun Robin Fu 	/*
3823c0da6274SZhi-Jun Robin Fu 	 * Properties have been setted up, so initialize the remaining
3824c0da6274SZhi-Jun Robin Fu 	 * bus_t fields
3825c0da6274SZhi-Jun Robin Fu 	 */
3826c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3827c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
3828c0da6274SZhi-Jun Robin Fu 
382926947304SEvan Yan 	return (PCICFG_SUCCESS);
383026947304SEvan Yan 
383126947304SEvan Yan failedchild:
383226947304SEvan Yan 	/*
383326947304SEvan Yan 	 * XXX check if it should be taken offline (if online)
383426947304SEvan Yan 	 */
383526947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
383626947304SEvan Yan 
3837c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3838c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_FINAL);
3839c0da6274SZhi-Jun Robin Fu 
384026947304SEvan Yan failedconfig:
384126947304SEvan Yan 
384226947304SEvan Yan 	(void) ndi_devi_free(new_child);
384326947304SEvan Yan 	return (ret);
384426947304SEvan Yan }
384526947304SEvan Yan 
384626947304SEvan Yan /*
384726947304SEvan Yan  * Sizing the BARs and update "reg" property
384826947304SEvan Yan  */
384926947304SEvan Yan static int
pcicfg_populate_reg_props(dev_info_t * new_child,ddi_acc_handle_t config_handle)385026947304SEvan Yan pcicfg_populate_reg_props(dev_info_t *new_child,
385126947304SEvan Yan     ddi_acc_handle_t config_handle)
385226947304SEvan Yan {
385326947304SEvan Yan 	int		i;
385426947304SEvan Yan 	uint32_t 	request;
385523c35297Sanish 
385623c35297Sanish 	i = PCI_CONF_BASE0;
385723c35297Sanish 
385823c35297Sanish 	while (i <= PCI_CONF_BASE5) {
385923c35297Sanish 
386023c35297Sanish 		pci_config_put32(config_handle, i, 0xffffffff);
386123c35297Sanish 
386223c35297Sanish 		request = pci_config_get32(config_handle, i);
386323c35297Sanish 		/*
386423c35297Sanish 		 * If its a zero length, don't do
386523c35297Sanish 		 * any programming.
386623c35297Sanish 		 */
386723c35297Sanish 		if (request != 0) {
386823c35297Sanish 			/*
386923c35297Sanish 			 * Add to the "reg" property
387023c35297Sanish 			 */
387123c35297Sanish 			if (pcicfg_update_reg_prop(new_child,
387223c35297Sanish 			    request, i) != PCICFG_SUCCESS) {
387323c35297Sanish 				goto failedchild;
387423c35297Sanish 			}
387523c35297Sanish 		} else {
387623c35297Sanish 			DEBUG1("BASE register [0x%x] asks for "
387723c35297Sanish 			    "[0x0]=[0x0](32)\n", i);
387823c35297Sanish 			i += 4;
387923c35297Sanish 			continue;
388023c35297Sanish 		}
388123c35297Sanish 
388223c35297Sanish 		/*
388323c35297Sanish 		 * Increment by eight if it is 64 bit address space
388423c35297Sanish 		 */
388523c35297Sanish 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
388623c35297Sanish 			DEBUG3("BASE register [0x%x] asks for "
388723c35297Sanish 			    "[0x%x]=[0x%x] (64)\n",
388826947304SEvan Yan 			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
388923c35297Sanish 			i += 8;
389023c35297Sanish 		} else {
389123c35297Sanish 			DEBUG3("BASE register [0x%x] asks for "
389223c35297Sanish 			    "[0x%x]=[0x%x](32)\n",
389326947304SEvan Yan 			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
389423c35297Sanish 			i += 4;
389523c35297Sanish 		}
389623c35297Sanish 	}
389723c35297Sanish 
389823c35297Sanish 	/*
389923c35297Sanish 	 * Get the ROM size and create register for it
390023c35297Sanish 	 */
390123c35297Sanish 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
390223c35297Sanish 
390323c35297Sanish 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
390423c35297Sanish 	/*
390523c35297Sanish 	 * If its a zero length, don't do
390623c35297Sanish 	 * any programming.
390723c35297Sanish 	 */
390823c35297Sanish 
390923c35297Sanish 	if (request != 0) {
391023c35297Sanish 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
391123c35297Sanish 		    PCI_CONF_ROM, request,
391223c35297Sanish 		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
391323c35297Sanish 		/*
391423c35297Sanish 		 * Add to the "reg" property
391523c35297Sanish 		 */
391626947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
391726947304SEvan Yan 		    != PCICFG_SUCCESS) {
391823c35297Sanish 			goto failedchild;
391923c35297Sanish 		}
392023c35297Sanish 	}
392123c35297Sanish 
392223c35297Sanish 	return (PCICFG_SUCCESS);
392323c35297Sanish 
392423c35297Sanish failedchild:
392526947304SEvan Yan 	return (PCICFG_FAILURE);
392626947304SEvan Yan }
392726947304SEvan Yan 
392823c35297Sanish /*
392926947304SEvan Yan  * Read the BARs and update properties. Used in virtual hotplug.
393023c35297Sanish  */
393126947304SEvan Yan static int
pcicfg_populate_props_from_bar(dev_info_t * new_child,ddi_acc_handle_t config_handle)393226947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child,
393326947304SEvan Yan     ddi_acc_handle_t config_handle)
393426947304SEvan Yan {
393526947304SEvan Yan 	uint32_t request, base, base_hi, size;
393626947304SEvan Yan 	int i;
393723c35297Sanish 
393826947304SEvan Yan 	i = PCI_CONF_BASE0;
393923c35297Sanish 
394026947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
394126947304SEvan Yan 		/*
394226947304SEvan Yan 		 * determine the size of the address space
394326947304SEvan Yan 		 */
394426947304SEvan Yan 		base = pci_config_get32(config_handle, i);
394526947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
394626947304SEvan Yan 		request = pci_config_get32(config_handle, i);
394726947304SEvan Yan 		pci_config_put32(config_handle, i, base);
394826947304SEvan Yan 
394926947304SEvan Yan 		/*
395026947304SEvan Yan 		 * If its a zero length, don't do any programming.
395126947304SEvan Yan 		 */
395226947304SEvan Yan 		if (request != 0) {
395326947304SEvan Yan 			/*
395426947304SEvan Yan 			 * Add to the "reg" property
395526947304SEvan Yan 			 */
395626947304SEvan Yan 			if (pcicfg_update_reg_prop(new_child,
395726947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
395826947304SEvan Yan 				goto failedchild;
395926947304SEvan Yan 			}
396026947304SEvan Yan 
396126947304SEvan Yan 			if ((PCI_BASE_SPACE_IO & request) == 0 &&
396226947304SEvan Yan 			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
396326947304SEvan Yan 				base_hi = pci_config_get32(config_handle, i+4);
396426947304SEvan Yan 			} else {
396526947304SEvan Yan 				base_hi = 0;
396626947304SEvan Yan 			}
396726947304SEvan Yan 			/*
396826947304SEvan Yan 			 * Add to "assigned-addresses" property
396926947304SEvan Yan 			 */
397026947304SEvan Yan 			size = (~(PCI_BASE_M_ADDR_M & request))+1;
397126947304SEvan Yan 			if (pcicfg_update_assigned_prop_value(new_child,
397226947304SEvan Yan 			    size, base, base_hi, i) != PCICFG_SUCCESS) {
397326947304SEvan Yan 				goto failedchild;
397426947304SEvan Yan 			}
397526947304SEvan Yan 		} else {
397626947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for [0x0]=[0x0]"
397726947304SEvan Yan 			    "(32)\n", i);
397826947304SEvan Yan 			i += 4;
397926947304SEvan Yan 			continue;
398026947304SEvan Yan 		}
398126947304SEvan Yan 
398226947304SEvan Yan 		/*
398326947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
398426947304SEvan Yan 		 */
398526947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
398626947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
398726947304SEvan Yan 			    "(64)\n", i, request,
398826947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
398926947304SEvan Yan 			i += 8;
399026947304SEvan Yan 		} else {
399126947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
399226947304SEvan Yan 			    "(32)\n", i, request,
399326947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
399426947304SEvan Yan 			i += 4;
399526947304SEvan Yan 		}
399626947304SEvan Yan 	}
399726947304SEvan Yan 
399826947304SEvan Yan 	/*
399926947304SEvan Yan 	 * Get the ROM size and create register for it
400026947304SEvan Yan 	 */
400126947304SEvan Yan 	base = pci_config_get32(config_handle, PCI_CONF_ROM);
400226947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
400326947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
400426947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, base);
400526947304SEvan Yan 
400626947304SEvan Yan 	/*
400726947304SEvan Yan 	 * If its a zero length, don't do
400826947304SEvan Yan 	 * any programming.
400926947304SEvan Yan 	 */
401026947304SEvan Yan 	if (request != 0) {
401126947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
401226947304SEvan Yan 		    PCI_CONF_ROM, request,
401326947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
401426947304SEvan Yan 		/*
401526947304SEvan Yan 		 * Add to the "reg" property
401626947304SEvan Yan 		 */
401726947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
401826947304SEvan Yan 		    != PCICFG_SUCCESS) {
401926947304SEvan Yan 			goto failedchild;
402026947304SEvan Yan 		}
402126947304SEvan Yan 		/*
402226947304SEvan Yan 		 * Add to "assigned-addresses" property
402326947304SEvan Yan 		 */
402426947304SEvan Yan 		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
402526947304SEvan Yan 		if (pcicfg_update_assigned_prop_value(new_child, size,
402626947304SEvan Yan 		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
402726947304SEvan Yan 			goto failedchild;
402826947304SEvan Yan 		}
402926947304SEvan Yan 	}
403026947304SEvan Yan 
403126947304SEvan Yan 	return (PCICFG_SUCCESS);
403226947304SEvan Yan 
403326947304SEvan Yan failedchild:
403426947304SEvan Yan 	return (PCICFG_FAILURE);
403523c35297Sanish }
403623c35297Sanish 
403723c35297Sanish 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)403823c35297Sanish pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
4039c0da6274SZhi-Jun Robin Fu     uint_t *highest_bus, boolean_t is_pcie)
404023c35297Sanish {
404123c35297Sanish 	uint64_t next_bus;
404223c35297Sanish 	uint_t new_bus, num_slots;
404323c35297Sanish 	ndi_ra_request_t req;
404423c35297Sanish 	int rval, i, j;
404523c35297Sanish 	uint64_t mem_answer, io_answer, mem_base, io_base, mem_alen, io_alen;
404623c35297Sanish 	uint64_t pf_mem_answer, pf_mem_base, pf_mem_alen;
404723c35297Sanish 	uint64_t mem_size, io_size, pf_mem_size;
404823c35297Sanish 	uint64_t mem_end, pf_mem_end, io_end;
404923c35297Sanish 	uint64_t round_answer, round_len;
405023c35297Sanish 	ppb_ranges_t range[PCICFG_RANGE_LEN];
405123c35297Sanish 	int bus_range[2];
405223c35297Sanish 	pcicfg_phdl_t phdl;
405323c35297Sanish 	int count;
405423c35297Sanish 	uint64_t pcibus_base, pcibus_alen;
405523c35297Sanish 	uint64_t max_bus;
405623c35297Sanish 	uint8_t pcie_device_type = 0;
405723c35297Sanish 	uint_t pf_mem_supported = 0;
405826947304SEvan Yan 	dev_info_t *new_device;
405926947304SEvan Yan 	int trans_device;
406026947304SEvan Yan 	int ari_mode = B_FALSE;
406126947304SEvan Yan 	int max_function = PCI_MAX_FUNCTIONS;
406223c35297Sanish 
406323c35297Sanish 	io_answer = io_base = io_alen = io_size = 0;
406423c35297Sanish 	pf_mem_answer = pf_mem_base = pf_mem_size = pf_mem_alen = 0;
406523c35297Sanish 
406623c35297Sanish 	/*
406726947304SEvan Yan 	 * Set "device_type" to "pci", the actual type will be set later
406826947304SEvan Yan 	 * by pcicfg_set_busnode_props() below. This is needed as the
406926947304SEvan Yan 	 * pcicfg_ra_free() below would update "available" property based
407026947304SEvan Yan 	 * on "device_type".
407126947304SEvan Yan 	 *
407226947304SEvan Yan 	 * This code can be removed later after PCI configurator is changed
407326947304SEvan Yan 	 * to use PCIRM, which automatically update properties upon allocation
407426947304SEvan Yan 	 * and free, at that time we'll be able to remove the code inside
407526947304SEvan Yan 	 * ndi_ra_alloc/free() which currently updates "available" property
407626947304SEvan Yan 	 * for pci/pcie devices in pcie fabric.
407726947304SEvan Yan 	 */
407826947304SEvan Yan 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
407926947304SEvan Yan 	    "device_type", "pci") != DDI_SUCCESS) {
408026947304SEvan Yan 		DEBUG0("Failed to set \"device_type\" props\n");
408126947304SEvan Yan 		return (PCICFG_FAILURE);
408226947304SEvan Yan 	}
408326947304SEvan Yan 
408426947304SEvan Yan 	/*
408523c35297Sanish 	 * setup resource maps for the bridge node
408623c35297Sanish 	 */
408723c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
408823c35297Sanish 	    == NDI_FAILURE) {
408923c35297Sanish 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
409023c35297Sanish 		rval = PCICFG_FAILURE;
409123c35297Sanish 		goto cleanup;
409223c35297Sanish 	}
409323c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
409423c35297Sanish 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
409523c35297Sanish 		rval = PCICFG_FAILURE;
409623c35297Sanish 		goto cleanup;
409723c35297Sanish 	}
409823c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
409923c35297Sanish 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
410023c35297Sanish 		rval = PCICFG_FAILURE;
410123c35297Sanish 		goto cleanup;
410223c35297Sanish 	}
410323c35297Sanish 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
410423c35297Sanish 	    NDI_FAILURE) {
410523c35297Sanish 		DEBUG0("Can not setup resource map -"
410623c35297Sanish 		    " NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
410723c35297Sanish 		rval = PCICFG_FAILURE;
410823c35297Sanish 		goto cleanup;
410923c35297Sanish 	}
411023c35297Sanish 
411123c35297Sanish 	/*
411223c35297Sanish 	 * Allocate bus range pool for the bridge.
411323c35297Sanish 	 */
411423c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
411523c35297Sanish 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
411623c35297Sanish 	req.ra_boundbase = 0;
411723c35297Sanish 	req.ra_boundlen = req.ra_len = (PCI_MAX_BUS_NUM -1);
411823c35297Sanish 	req.ra_align_mask = 0;  /* no alignment needed */
411923c35297Sanish 
412023c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
412123c35297Sanish 	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
412223c35297Sanish 
412323c35297Sanish 	if (rval != NDI_SUCCESS) {
412423c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
412523c35297Sanish 			/*EMPTY*/
412623c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
412723c35297Sanish 		} else {
412823c35297Sanish 			DEBUG0(
412923c35297Sanish 			    "Failed to allocate bus range for bridge\n");
41305af4ae46Sjveta 			rval = PCICFG_NORESRC;
413123c35297Sanish 			goto cleanup;
413223c35297Sanish 		}
413323c35297Sanish 	}
413423c35297Sanish 
413523c35297Sanish 	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
413623c35297Sanish 	    pcibus_base, pcibus_alen);
413723c35297Sanish 
413823c35297Sanish 	/*
413923c35297Sanish 	 * Put available bus range into the pool.
414023c35297Sanish 	 * Take the first one for this bridge to use and don't give
414123c35297Sanish 	 * to child.
414223c35297Sanish 	 */
414323c35297Sanish 	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
414423c35297Sanish 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
414523c35297Sanish 
414623c35297Sanish 	next_bus = pcibus_base;
414723c35297Sanish 	max_bus = pcibus_base + pcibus_alen - 1;
414823c35297Sanish 
414923c35297Sanish 	new_bus = next_bus;
415023c35297Sanish 
415123c35297Sanish 	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
415223c35297Sanish 
415323c35297Sanish 	/* Keep track of highest bus for subordinate bus programming */
415423c35297Sanish 	*highest_bus = new_bus;
415523c35297Sanish 
415623c35297Sanish 	/*
415723c35297Sanish 	 * Allocate (non-prefetchable) Memory Space for Bridge
415823c35297Sanish 	 */
415923c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
416023c35297Sanish 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
416123c35297Sanish 	req.ra_boundbase = 0;
416223c35297Sanish 	/*
416323c35297Sanish 	 * limit the boundlen,len to a 32b quantity. It should be Ok to
416423c35297Sanish 	 * lose alignment-based-size of resource due to this.
416523c35297Sanish 	 */
416623c35297Sanish 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
416723c35297Sanish 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
416823c35297Sanish 	req.ra_align_mask =
416923c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
417023c35297Sanish 
417123c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
417223c35297Sanish 	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
417323c35297Sanish 
417423c35297Sanish 	if (rval != NDI_SUCCESS) {
417523c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
417623c35297Sanish 			/*EMPTY*/
417723c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
417823c35297Sanish 		} else {
417923c35297Sanish 			DEBUG0(
418023c35297Sanish 			    "Failed to allocate memory for bridge\n");
41815af4ae46Sjveta 			rval = PCICFG_NORESRC;
418223c35297Sanish 			goto cleanup;
418323c35297Sanish 		}
418423c35297Sanish 	}
418523c35297Sanish 
418623c35297Sanish 	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
418723c35297Sanish 	    PCICFG_HIADDR(mem_answer),
418823c35297Sanish 	    PCICFG_LOADDR(mem_answer),
418923c35297Sanish 	    mem_alen);
419023c35297Sanish 
419123c35297Sanish 	/*
419223c35297Sanish 	 * Put available memory into the pool.
419323c35297Sanish 	 */
419423c35297Sanish 	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
419523c35297Sanish 	    NDI_RA_PASS);
419623c35297Sanish 
419723c35297Sanish 	mem_base = mem_answer;
419823c35297Sanish 
419923c35297Sanish 	/*
420023c35297Sanish 	 * Allocate I/O Space for Bridge
420123c35297Sanish 	 */
420223c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
420323c35297Sanish 	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
420423c35297Sanish 	req.ra_boundbase = 0;
420523c35297Sanish 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
420623c35297Sanish 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
420723c35297Sanish 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
420823c35297Sanish 
420923c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
421023c35297Sanish 	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
421123c35297Sanish 
421223c35297Sanish 	if (rval != NDI_SUCCESS) {
421323c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
421423c35297Sanish 			/*EMPTY*/
421523c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
421623c35297Sanish 		} else {
421723c35297Sanish 			DEBUG0("Failed to allocate io space for bridge\n");
421823c35297Sanish 			/* i/o space is an optional requirement so continue */
421923c35297Sanish 		}
422023c35297Sanish 	}
422123c35297Sanish 
422223c35297Sanish 	DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
422323c35297Sanish 	    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), io_alen);
422423c35297Sanish 
422523c35297Sanish 	/*
422623c35297Sanish 	 * Put available I/O into the pool.
422723c35297Sanish 	 */
422823c35297Sanish 	(void) ndi_ra_free(new_child, io_answer, io_alen, NDI_RA_TYPE_IO,
422923c35297Sanish 	    NDI_RA_PASS);
423023c35297Sanish 
423123c35297Sanish 	io_base = io_answer;
423223c35297Sanish 
423323c35297Sanish 	/*
423423c35297Sanish 	 * Check if the bridge supports Prefetchable memory range.
423523c35297Sanish 	 * If it does, then we setup PF memory range for the bridge.
423623c35297Sanish 	 * Otherwise, we skip the step of setting up PF memory
423723c35297Sanish 	 * range for it. This could cause config operation to
423823c35297Sanish 	 * fail if any devices under the bridge need PF memory.
423923c35297Sanish 	 */
424023c35297Sanish 	/* write a non zero value to the PF BASE register */
424123c35297Sanish 	pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
424223c35297Sanish 	/* if the read returns zero then PF range is not supported */
424323c35297Sanish 	if (pci_config_get16(h, PCI_BCNF_PF_BASE_LOW) == 0) {
424423c35297Sanish 		/* bridge doesn't support PF memory range */
424523c35297Sanish 		goto pf_setup_end;
424623c35297Sanish 	} else {
424723c35297Sanish 		pf_mem_supported = 1;
424823c35297Sanish 		/* reset the PF BASE register */
424923c35297Sanish 		pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0);
425023c35297Sanish 	}
425123c35297Sanish 
425223c35297Sanish 	/*
425323c35297Sanish 	 * Bridge supports PF mem range; Allocate PF Memory Space for it.
425423c35297Sanish 	 *
425523c35297Sanish 	 * Note: Both non-prefetchable and prefetchable memory space
425623c35297Sanish 	 * allocations are made within 32bit space. Currently, BIOSs
425723c35297Sanish 	 * allocate device memory for PCI devices within the 32bit space
425823c35297Sanish 	 * so this will not be a problem.
425923c35297Sanish 	 */
426023c35297Sanish 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
426123c35297Sanish 	req.ra_flags = NDI_RA_ALLOC_PARTIAL_OK | NDI_RA_ALLOC_BOUNDED;
426223c35297Sanish 	req.ra_boundbase = 0;
426323c35297Sanish 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
426423c35297Sanish 	req.ra_align_mask =
426523c35297Sanish 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
426623c35297Sanish 
426723c35297Sanish 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
426823c35297Sanish 	    &pf_mem_answer, &pf_mem_alen,  NDI_RA_TYPE_PCI_PREFETCH_MEM,
426923c35297Sanish 	    NDI_RA_PASS);
427023c35297Sanish 
427123c35297Sanish 	if (rval != NDI_SUCCESS) {
427223c35297Sanish 		if (rval == NDI_RA_PARTIAL_REQ) {
427323c35297Sanish 			/*EMPTY*/
427423c35297Sanish 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
427523c35297Sanish 		} else {
427623c35297Sanish 			DEBUG0(
427723c35297Sanish 			    "Failed to allocate PF memory for bridge\n");
427823c35297Sanish 			/* PF mem is an optional requirement so continue */
427923c35297Sanish 		}
428023c35297Sanish 	}
428123c35297Sanish 
428223c35297Sanish 	DEBUG3("Bridge PF Memory Allocated [0x%x.%x] len [0x%x]\n",
428323c35297Sanish 	    PCICFG_HIADDR(pf_mem_answer),
428423c35297Sanish 	    PCICFG_LOADDR(pf_mem_answer),
428523c35297Sanish 	    pf_mem_alen);
428623c35297Sanish 
428723c35297Sanish 	/*
428823c35297Sanish 	 * Put available PF memory into the pool.
428923c35297Sanish 	 */
429023c35297Sanish 	(void) ndi_ra_free(new_child, pf_mem_answer, pf_mem_alen,
429123c35297Sanish 	    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
429223c35297Sanish 
429323c35297Sanish 	pf_mem_base = pf_mem_answer;
429423c35297Sanish 
429523c35297Sanish 	/*
429623c35297Sanish 	 * Program the PF memory base register with the
429723c35297Sanish 	 * start of the memory range
429823c35297Sanish 	 */
429923c35297Sanish 	pci_config_put16(h, PCI_BCNF_PF_BASE_LOW,
430023c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_answer)));
430123c35297Sanish 	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH,
430223c35297Sanish 	    PCICFG_HIADDR(pf_mem_answer));
430323c35297Sanish 
430423c35297Sanish 	/*
430523c35297Sanish 	 * Program the PF memory limit register with the
430623c35297Sanish 	 * end of the memory range.
430723c35297Sanish 	 */
430823c35297Sanish 	pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
430923c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
431023c35297Sanish 	    PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
431123c35297Sanish 	    PCICFG_MEMGRAN) - 1)));
431223c35297Sanish 	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
431323c35297Sanish 	    PCICFG_HIADDR(PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
431423c35297Sanish 	    PCICFG_MEMGRAN) - 1));
431523c35297Sanish 
431623c35297Sanish 	/*
431723c35297Sanish 	 * Allocate the chunk of PF memory (if any) not programmed into the
431823c35297Sanish 	 * bridge because of the round down.
431923c35297Sanish 	 */
432023c35297Sanish 	if (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen), PCICFG_MEMGRAN)
432123c35297Sanish 	    != (pf_mem_answer + pf_mem_alen)) {
432223c35297Sanish 		DEBUG0("Need to allocate Memory round off chunk\n");
432323c35297Sanish 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
432423c35297Sanish 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
432523c35297Sanish 		req.ra_addr = PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
432623c35297Sanish 		    PCICFG_MEMGRAN);
432723c35297Sanish 		req.ra_len =  (pf_mem_answer + pf_mem_alen) -
432823c35297Sanish 		    (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
432923c35297Sanish 		    PCICFG_MEMGRAN));
433023c35297Sanish 
433123c35297Sanish 		(void) ndi_ra_alloc(new_child, &req,
433223c35297Sanish 		    &round_answer, &round_len,  NDI_RA_TYPE_PCI_PREFETCH_MEM,
433323c35297Sanish 		    NDI_RA_PASS);
433423c35297Sanish 	}
433523c35297Sanish 
433623c35297Sanish pf_setup_end:
433723c35297Sanish 
433823c35297Sanish 	/*
433923c35297Sanish 	 * Program the memory base register with the
434023c35297Sanish 	 * start of the memory range
434123c35297Sanish 	 */
434223c35297Sanish 	pci_config_put16(h, PCI_BCNF_MEM_BASE,
434323c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
434423c35297Sanish 
434523c35297Sanish 	/*
434623c35297Sanish 	 * Program the memory limit register with the
434723c35297Sanish 	 * end of the memory range.
434823c35297Sanish 	 */
434923c35297Sanish 
435023c35297Sanish 	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
435123c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
435223c35297Sanish 	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
435323c35297Sanish 
435423c35297Sanish 	/*
435523c35297Sanish 	 * Allocate the chunk of memory (if any) not programmed into the
435623c35297Sanish 	 * bridge because of the round down.
435723c35297Sanish 	 */
435823c35297Sanish 	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
435923c35297Sanish 	    != (mem_answer + mem_alen)) {
436023c35297Sanish 		DEBUG0("Need to allocate Memory round off chunk\n");
436123c35297Sanish 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
436223c35297Sanish 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
436323c35297Sanish 		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
436423c35297Sanish 		    PCICFG_MEMGRAN);
436523c35297Sanish 		req.ra_len =  (mem_answer + mem_alen) -
436623c35297Sanish 		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
436723c35297Sanish 		    PCICFG_MEMGRAN));
436823c35297Sanish 
436923c35297Sanish 		(void) ndi_ra_alloc(new_child, &req,
437023c35297Sanish 		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
437123c35297Sanish 	}
437223c35297Sanish 
437323c35297Sanish 	/*
437423c35297Sanish 	 * Program the I/O Space Base
437523c35297Sanish 	 */
437623c35297Sanish 	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
437723c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(
437823c35297Sanish 	    PCICFG_LOADDR(io_answer))));
437923c35297Sanish 
438023c35297Sanish 	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
438123c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
438223c35297Sanish 
438323c35297Sanish 	/*
438423c35297Sanish 	 * Program the I/O Space Limit
438523c35297Sanish 	 */
438623c35297Sanish 	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
438723c35297Sanish 	    PCICFG_HIBYTE(PCICFG_LOWORD(
438823c35297Sanish 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
438923c35297Sanish 	    PCICFG_IOGRAN)))) - 1);
439023c35297Sanish 
439123c35297Sanish 	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
439223c35297Sanish 	    PCICFG_HIWORD(PCICFG_LOADDR(
439323c35297Sanish 	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
439423c35297Sanish 	    - 1);
439523c35297Sanish 
439623c35297Sanish 	/*
439723c35297Sanish 	 * Allocate the chunk of I/O (if any) not programmed into the
439823c35297Sanish 	 * bridge because of the round down.
439923c35297Sanish 	 */
440023c35297Sanish 	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
440123c35297Sanish 	    != (io_answer + io_alen)) {
440223c35297Sanish 		DEBUG0("Need to allocate I/O round off chunk\n");
440323c35297Sanish 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
440423c35297Sanish 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
440523c35297Sanish 		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
440623c35297Sanish 		    PCICFG_IOGRAN);
440723c35297Sanish 		req.ra_len =  (io_answer + io_alen) -
440823c35297Sanish 		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
440923c35297Sanish 		    PCICFG_IOGRAN));
441023c35297Sanish 
441123c35297Sanish 		(void) ndi_ra_alloc(new_child, &req,
441223c35297Sanish 		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
441323c35297Sanish 	}
441423c35297Sanish 
441523c35297Sanish 	(void) pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
441623c35297Sanish 
441723c35297Sanish 	/*
44183f9ec228SZhi-Jun Robin Fu 	 * Setup "ranges" and "bus-range" properties before onlining
44193f9ec228SZhi-Jun Robin Fu 	 * the bridge.
44203f9ec228SZhi-Jun Robin Fu 	 */
44213f9ec228SZhi-Jun Robin Fu 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
44223f9ec228SZhi-Jun Robin Fu 
44233f9ec228SZhi-Jun Robin Fu 	range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
44243f9ec228SZhi-Jun Robin Fu 	    PCI_ADDR_IO);
44253f9ec228SZhi-Jun Robin Fu 	range[0].child_low = range[0].parent_low = io_base;
44263f9ec228SZhi-Jun Robin Fu 	range[1].child_high = range[1].parent_high |=
44273f9ec228SZhi-Jun Robin Fu 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
44283f9ec228SZhi-Jun Robin Fu 	range[1].child_low = range[1].parent_low = mem_base;
44293f9ec228SZhi-Jun Robin Fu 	range[2].child_high = range[2].parent_high |=
44303f9ec228SZhi-Jun Robin Fu 	    (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
44313f9ec228SZhi-Jun Robin Fu 	range[2].child_low = range[2].parent_low = pf_mem_base;
44323f9ec228SZhi-Jun Robin Fu 
44333f9ec228SZhi-Jun Robin Fu 	range[0].size_low = io_alen;
44343f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[0]);
44353f9ec228SZhi-Jun Robin Fu 	range[1].size_low = mem_alen;
44363f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[1]);
44373f9ec228SZhi-Jun Robin Fu 	range[2].size_low = pf_mem_alen;
44383f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[2]);
44393f9ec228SZhi-Jun Robin Fu 
44403f9ec228SZhi-Jun Robin Fu 	bus_range[0] = new_bus;
44413f9ec228SZhi-Jun Robin Fu 	bus_range[1] = max_bus;
44423f9ec228SZhi-Jun Robin Fu 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
44433f9ec228SZhi-Jun Robin Fu 	    "bus-range", bus_range, 2);
44443f9ec228SZhi-Jun Robin Fu 
44453f9ec228SZhi-Jun Robin Fu 	/*
444623c35297Sanish 	 * Reset the secondary bus
444723c35297Sanish 	 */
444823c35297Sanish 	pci_config_put16(h, PCI_BCNF_BCNTRL,
444923c35297Sanish 	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
445023c35297Sanish 
445123c35297Sanish 	drv_usecwait(100);
445223c35297Sanish 
445323c35297Sanish 	pci_config_put16(h, PCI_BCNF_BCNTRL,
445423c35297Sanish 	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
445523c35297Sanish 
445623c35297Sanish 	/*
445723c35297Sanish 	 * Clear status bits
445823c35297Sanish 	 */
445923c35297Sanish 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
446023c35297Sanish 
446123c35297Sanish 	/*
446223c35297Sanish 	 * Needs to be set to this value
446323c35297Sanish 	 */
446423c35297Sanish 	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
446523c35297Sanish 
446623c35297Sanish 	/* check our device_type as defined by Open Firmware */
446723c35297Sanish 	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
446823c35297Sanish 		pcie_device_type = 1;
446923c35297Sanish 
447023c35297Sanish 	/*
447123c35297Sanish 	 * Set bus properties
447223c35297Sanish 	 */
447323c35297Sanish 	if (pcicfg_set_busnode_props(new_child, pcie_device_type)
447423c35297Sanish 	    != PCICFG_SUCCESS) {
447523c35297Sanish 		DEBUG0("Failed to set busnode props\n");
447623c35297Sanish 		rval = PCICFG_FAILURE;
447723c35297Sanish 		goto cleanup;
447823c35297Sanish 	}
447923c35297Sanish 
448023c35297Sanish 	(void) pcicfg_device_on(h);
448123c35297Sanish 
4482c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4483c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
448423c35297Sanish 	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
448523c35297Sanish 	    != NDI_SUCCESS) {
448623c35297Sanish 		DEBUG0("Unable to online bridge\n");
448723c35297Sanish 		rval = PCICFG_FAILURE;
448823c35297Sanish 		goto cleanup;
448923c35297Sanish 	}
449023c35297Sanish 
449123c35297Sanish 	DEBUG0("Bridge is ONLINE\n");
449223c35297Sanish 
449323c35297Sanish 	/*
449423c35297Sanish 	 * After a Reset, we need to wait 2^25 clock cycles before the
449523c35297Sanish 	 * first Configuration access.  The worst case is 33MHz, which
449623c35297Sanish 	 * is a 1 second wait.
449723c35297Sanish 	 */
449823c35297Sanish 	drv_usecwait(pcicfg_sec_reset_delay);
449923c35297Sanish 
450023c35297Sanish 	/*
450123c35297Sanish 	 * Probe all children devices
450223c35297Sanish 	 */
450323c35297Sanish 	DEBUG0("Bridge Programming Complete - probe children\n");
450423c35297Sanish 	ndi_devi_enter(new_child, &count);
450526947304SEvan Yan 	for (i = 0; ((i < PCI_MAX_DEVICES) && (ari_mode == B_FALSE));
450626947304SEvan Yan 	    i++) {
450726947304SEvan Yan 		for (j = 0; j < max_function; ) {
450826947304SEvan Yan 			if (ari_mode)
450926947304SEvan Yan 				trans_device = j >> 3;
451026947304SEvan Yan 			else
451126947304SEvan Yan 				trans_device = i;
451226947304SEvan Yan 
451323c35297Sanish 			if ((rval = pcicfg_probe_children(new_child,
4514c0da6274SZhi-Jun Robin Fu 			    new_bus, trans_device, j & 7, highest_bus,
4515c0da6274SZhi-Jun Robin Fu 			    0, is_pcie)) != PCICFG_SUCCESS) {
451623c35297Sanish 				if (rval == PCICFG_NODEVICE) {
451723c35297Sanish 					DEBUG3("No Device at bus [0x%x]"
451823c35297Sanish 					    "device [0x%x] "
451926947304SEvan Yan 					    "func [0x%x]\n", new_bus,
452026947304SEvan Yan 					    trans_device, j & 7);
452126947304SEvan Yan 
452223c35297Sanish 					if (j)
452326947304SEvan Yan 						goto next;
452423c35297Sanish 				} else
452523c35297Sanish 					/*EMPTY*/
452623c35297Sanish 					DEBUG3("Failed to configure bus "
452723c35297Sanish 					    "[0x%x] device [0x%x] "
452826947304SEvan Yan 					    "func [0x%x]\n", new_bus,
452926947304SEvan Yan 					    trans_device, j & 7);
453023c35297Sanish 				break;
453123c35297Sanish 			}
453226947304SEvan Yan next:
453326947304SEvan Yan 			new_device = pcicfg_devi_find(new_child, trans_device,
453426947304SEvan Yan 			    (j & 7));
453526947304SEvan Yan 
453626947304SEvan Yan 			/*
453726947304SEvan Yan 			 * Determine if ARI Forwarding should be enabled.
453826947304SEvan Yan 			 */
453926947304SEvan Yan 			if (j == 0) {
454026947304SEvan Yan 				if (new_device == NULL)
454126947304SEvan Yan 					break;
454226947304SEvan Yan 
454326947304SEvan Yan 				if ((pcie_ari_supported(new_child) ==
454426947304SEvan Yan 				    PCIE_ARI_FORW_SUPPORTED) &&
454526947304SEvan Yan 				    (pcie_ari_device(new_device) ==
454626947304SEvan Yan 				    PCIE_ARI_DEVICE)) {
454726947304SEvan Yan 					if (pcie_ari_enable(new_child) ==
454826947304SEvan Yan 					    DDI_SUCCESS) {
454926947304SEvan Yan 						(void) ddi_prop_create(
455026947304SEvan Yan 						    DDI_DEV_T_NONE,
455126947304SEvan Yan 						    new_child,
455226947304SEvan Yan 						    DDI_PROP_CANSLEEP,
455326947304SEvan Yan 						    "ari-enabled", NULL, 0);
455426947304SEvan Yan 						ari_mode = B_TRUE;
455526947304SEvan Yan 						max_function =
455626947304SEvan Yan 						    PCICFG_MAX_ARI_FUNCTION;
455726947304SEvan Yan 					}
455826947304SEvan Yan 				}
455926947304SEvan Yan 			}
456026947304SEvan Yan 			if (ari_mode == B_TRUE) {
456126947304SEvan Yan 				int next_function;
456226947304SEvan Yan 
456326947304SEvan Yan 				if (new_device == NULL)
456426947304SEvan Yan 					break;
456526947304SEvan Yan 
456626947304SEvan Yan 				if (pcie_ari_get_next_function(new_device,
456726947304SEvan Yan 				    &next_function) != DDI_SUCCESS)
456826947304SEvan Yan 					break;
456926947304SEvan Yan 
457026947304SEvan Yan 				j = next_function;
457126947304SEvan Yan 
457226947304SEvan Yan 				if (next_function == 0)
457326947304SEvan Yan 					break;
457426947304SEvan Yan 			} else
457526947304SEvan Yan 				j++;
457626947304SEvan Yan 
457723c35297Sanish 		}
457823c35297Sanish 		/* if any function fails to be configured, no need to proceed */
457923c35297Sanish 		if (rval != PCICFG_NODEVICE)
458023c35297Sanish 			break;
458123c35297Sanish 	}
458223c35297Sanish 	ndi_devi_exit(new_child, count);
458323c35297Sanish 
458423c35297Sanish 	/*
458523c35297Sanish 	 * Offline the bridge to allow reprogramming of resources.
458626947304SEvan Yan 	 *
458726947304SEvan Yan 	 * This should always succeed since nobody else has started to
458826947304SEvan Yan 	 * use it yet, failing to detach the driver would indicate a bug.
458926947304SEvan Yan 	 * Also in that case it's better just panic than allowing the
459026947304SEvan Yan 	 * configurator to proceed with BAR reprogramming without bridge
459126947304SEvan Yan 	 * driver detached.
459223c35297Sanish 	 */
459326947304SEvan Yan 	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
459426947304SEvan Yan 	    == NDI_SUCCESS);
4595c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4596c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
459723c35297Sanish 
459823c35297Sanish 	phdl.dip = new_child;
459923c35297Sanish 	phdl.memory_base = mem_answer;
460023c35297Sanish 	phdl.io_base = io_answer;
460123c35297Sanish 	phdl.pf_memory_base = pf_mem_answer;
460223c35297Sanish 	phdl.error = PCICFG_SUCCESS;	/* in case of empty child tree */
460323c35297Sanish 
460423c35297Sanish 	ndi_devi_enter(ddi_get_parent(new_child), &count);
460523c35297Sanish 	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
460623c35297Sanish 	ndi_devi_exit(ddi_get_parent(new_child), count);
460723c35297Sanish 
460823c35297Sanish 	num_slots = pcicfg_get_nslots(new_child, h);
460923c35297Sanish 	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
461023c35297Sanish 	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
461123c35297Sanish 	pf_mem_end = PCICFG_ROUND_UP(phdl.pf_memory_base, PCICFG_MEMGRAN);
461223c35297Sanish 
461326947304SEvan Yan 	DEBUG4("Start of Unallocated Bridge(%d slots) Resources Mem=0x%lx "
461426947304SEvan Yan 	    "I/O=0x%lx PF_mem=%x%lx\n", num_slots, mem_end, io_end, pf_mem_end);
461523c35297Sanish 
461623c35297Sanish 	/*
461726947304SEvan Yan 	 * Before probing the children we've allocated maximum MEM/IO
461826947304SEvan Yan 	 * resources from parent, and updated "available" property
461926947304SEvan Yan 	 * accordingly. Later we'll be giving up unused resources to
462026947304SEvan Yan 	 * the parent, thus we need to destroy "available" property
462126947304SEvan Yan 	 * here otherwise it will be out-of-sync with the actual free
462226947304SEvan Yan 	 * resources this bridge has. This property will be rebuilt below
462326947304SEvan Yan 	 * with the actual free resources reserved for hotplug slots
462426947304SEvan Yan 	 * (if any).
462526947304SEvan Yan 	 */
462626947304SEvan Yan 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
462726947304SEvan Yan 	/*
462823c35297Sanish 	 * if the bridge a slots, then preallocate. If not, assume static
462923c35297Sanish 	 * configuration. Also check for preallocation limits and spit
463023c35297Sanish 	 * warning messages appropriately (perhaps some can be in debug mode).
463123c35297Sanish 	 */
463223c35297Sanish 	if (num_slots) {
463326947304SEvan Yan 		uint64_t mem_reqd = mem_answer +
463426947304SEvan Yan 		    (num_slots * pcicfg_slot_memsize);
463526947304SEvan Yan 		uint64_t io_reqd = io_answer +
463626947304SEvan Yan 		    (num_slots * pcicfg_slot_iosize);
463726947304SEvan Yan 		uint64_t pf_mem_reqd = pf_mem_answer +
463826947304SEvan Yan 		    (num_slots * pcicfg_slot_pf_memsize);
463926947304SEvan Yan 		uint8_t highest_bus_reqd = new_bus +
464026947304SEvan Yan 		    (num_slots * pcicfg_slot_busnums);
4641949b8557Sarutz #ifdef DEBUG
464223c35297Sanish 		if (mem_end > mem_reqd)
4643949b8557Sarutz 			DEBUG3("Memory space consumed by bridge more "
464423c35297Sanish 			    "than planned for %d slot(s)(%" PRIx64 ",%"
464523c35297Sanish 			    PRIx64 ")", num_slots, mem_answer, mem_end);
464623c35297Sanish 		if (io_end > io_reqd)
4647949b8557Sarutz 			DEBUG3("IO space consumed by bridge more than"
464823c35297Sanish 			    " planned for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
464923c35297Sanish 			    num_slots, io_answer, io_end);
465023c35297Sanish 		if (pf_mem_end > pf_mem_reqd)
4651949b8557Sarutz 			DEBUG3("PF Memory space consumed by bridge"
465223c35297Sanish 			    " more than planned for %d slot(s)(%" PRIx64 ",%"
465323c35297Sanish 			    PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
465423c35297Sanish 		if (*highest_bus > highest_bus_reqd)
4655949b8557Sarutz 			DEBUG3("Buses consumed by bridge more "
465623c35297Sanish 			    "than planned for %d slot(s)(%x, %x)",
465723c35297Sanish 			    num_slots, new_bus, *highest_bus);
465823c35297Sanish 
465923c35297Sanish 		if (mem_reqd > (mem_answer + mem_alen))
4660949b8557Sarutz 			DEBUG3("Memory space required by bridge more "
466123c35297Sanish 			    "than available for %d slot(s)(%" PRIx64 ",%"
466223c35297Sanish 			    PRIx64 ")", num_slots, mem_answer, mem_end);
466323c35297Sanish 		if (io_reqd > (io_answer + io_alen))
4664949b8557Sarutz 			DEBUG3("IO space required by bridge more than"
466523c35297Sanish 			    "available for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
466623c35297Sanish 			    num_slots, io_answer, io_end);
466723c35297Sanish 		if (pf_mem_reqd > (pf_mem_answer + pf_mem_alen))
4668949b8557Sarutz 			DEBUG3("PF Memory space required by bridge"
466923c35297Sanish 			    " more than available for %d slot(s)(%" PRIx64 ",%"
467023c35297Sanish 			    PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
467123c35297Sanish 		if (highest_bus_reqd > max_bus)
4672949b8557Sarutz 			DEBUG3("Bus numbers required by bridge more "
467323c35297Sanish 			    "than available for %d slot(s)(%x, %x)",
467423c35297Sanish 			    num_slots, new_bus, *highest_bus);
4675949b8557Sarutz #endif
467623c35297Sanish 		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
467723c35297Sanish 		    mem_end);
467823c35297Sanish 		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
467923c35297Sanish 		pf_mem_end = MAX((MIN(pf_mem_reqd, (pf_mem_answer +
468023c35297Sanish 		    pf_mem_alen))), pf_mem_end);
468123c35297Sanish 		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
468223c35297Sanish 		    *highest_bus);
468323c35297Sanish 		DEBUG4("mem_end %lx, io_end %lx, pf_mem_end %lx"
468426947304SEvan Yan 		    " highest_bus %x\n", mem_end, io_end, pf_mem_end,
468526947304SEvan Yan 		    *highest_bus);
468623c35297Sanish 	}
468723c35297Sanish 
468823c35297Sanish 	/*
468923c35297Sanish 	 * Give back unused memory space to parent.
469023c35297Sanish 	 */
469126947304SEvan Yan 	(void) ndi_ra_free(ddi_get_parent(new_child), mem_end,
469226947304SEvan Yan 	    (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, NDI_RA_PASS);
469323c35297Sanish 
469423c35297Sanish 	if (mem_end == mem_answer) {
469523c35297Sanish 		DEBUG0("No memory resources used\n");
469623c35297Sanish 		/*
469723c35297Sanish 		 * To prevent the bridge from forwarding any Memory
469823c35297Sanish 		 * transactions, the Memory Limit will be programmed
469923c35297Sanish 		 * with a smaller value than the Memory Base.
470023c35297Sanish 		 */
470123c35297Sanish 		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
470223c35297Sanish 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
470323c35297Sanish 
470423c35297Sanish 		mem_size = 0;
470523c35297Sanish 	} else {
470623c35297Sanish 		/*
470723c35297Sanish 		 * Reprogram the end of the memory.
470823c35297Sanish 		 */
470923c35297Sanish 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
471023c35297Sanish 		    PCICFG_HIWORD(mem_end) - 1);
471123c35297Sanish 		mem_size = mem_end - mem_base;
471223c35297Sanish 	}
471323c35297Sanish 
471423c35297Sanish 	/*
471523c35297Sanish 	 * Give back unused io space to parent.
471623c35297Sanish 	 */
471723c35297Sanish 	(void) ndi_ra_free(ddi_get_parent(new_child),
471823c35297Sanish 	    io_end, (io_answer + io_alen) - io_end,
471923c35297Sanish 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
472023c35297Sanish 
472123c35297Sanish 	if (io_end == io_answer) {
472223c35297Sanish 		DEBUG0("No IO Space resources used\n");
472323c35297Sanish 
472423c35297Sanish 		/*
472523c35297Sanish 		 * To prevent the bridge from forwarding any I/O
472623c35297Sanish 		 * transactions, the I/O Limit will be programmed
472723c35297Sanish 		 * with a smaller value than the I/O Base.
472823c35297Sanish 		 */
472923c35297Sanish 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
473023c35297Sanish 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
473123c35297Sanish 		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
473223c35297Sanish 		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
473323c35297Sanish 
473423c35297Sanish 		io_size = 0;
473523c35297Sanish 	} else {
473623c35297Sanish 		/*
473723c35297Sanish 		 * Reprogram the end of the io space.
473823c35297Sanish 		 */
473923c35297Sanish 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
474023c35297Sanish 		    PCICFG_HIBYTE(PCICFG_LOWORD(
474123c35297Sanish 		    PCICFG_LOADDR(io_end) - 1)));
474223c35297Sanish 
474323c35297Sanish 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
474423c35297Sanish 		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
474523c35297Sanish 
474623c35297Sanish 		io_size = io_end - io_base;
474723c35297Sanish 	}
474823c35297Sanish 
474923c35297Sanish 	/*
475023c35297Sanish 	 * Give back unused PF memory space to parent.
475123c35297Sanish 	 */
475223c35297Sanish 	if (pf_mem_supported) {
475323c35297Sanish 		(void) ndi_ra_free(ddi_get_parent(new_child),
475423c35297Sanish 		    pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
475523c35297Sanish 		    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
475623c35297Sanish 
475723c35297Sanish 		if (pf_mem_end == pf_mem_answer) {
475823c35297Sanish 			DEBUG0("No PF memory resources used\n");
475923c35297Sanish 			/*
476023c35297Sanish 			 * To prevent the bridge from forwarding any PF Memory
476123c35297Sanish 			 * transactions, the PF Memory Limit will be programmed
476223c35297Sanish 			 * with a smaller value than the Memory Base.
476323c35297Sanish 			 */
476423c35297Sanish 			pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
476523c35297Sanish 			pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
476623c35297Sanish 			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
476723c35297Sanish 			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
476823c35297Sanish 
476923c35297Sanish 			pf_mem_size = 0;
477023c35297Sanish 		} else {
477123c35297Sanish 			/*
477223c35297Sanish 			 * Reprogram the end of the PF memory range.
477323c35297Sanish 			 */
477423c35297Sanish 			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
477523c35297Sanish 			    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
477623c35297Sanish 			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
477723c35297Sanish 			    PCICFG_HIADDR(pf_mem_end - 1));
477823c35297Sanish 			pf_mem_size = pf_mem_end - pf_mem_base;
477923c35297Sanish 		}
478023c35297Sanish 	}
478123c35297Sanish 
478223c35297Sanish 	if ((max_bus - *highest_bus) > 0) {
478323c35297Sanish 		/*
478423c35297Sanish 		 * Give back unused bus numbers
478523c35297Sanish 		 */
478623c35297Sanish 		(void) ndi_ra_free(ddi_get_parent(new_child),
478723c35297Sanish 		    *highest_bus+1, max_bus - *highest_bus,
478823c35297Sanish 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
478923c35297Sanish 	}
479023c35297Sanish 
479123c35297Sanish 	/*
479223c35297Sanish 	 * Set bus numbers to ranges encountered during scan
479323c35297Sanish 	 */
479423c35297Sanish 	(void) pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
479523c35297Sanish 
479623c35297Sanish 	/*
479723c35297Sanish 	 * Remove the ranges property if it exists since we will create
479823c35297Sanish 	 * a new one.
479923c35297Sanish 	 */
480023c35297Sanish 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
480123c35297Sanish 
480223c35297Sanish 	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
480323c35297Sanish 	    mem_base, mem_size);
480423c35297Sanish 	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
480523c35297Sanish 	    io_base, io_size);
480623c35297Sanish 	DEBUG2("                         - PF Mem address %lx PF Mem Size %x\n",
480723c35297Sanish 	    pf_mem_base, pf_mem_size);
480823c35297Sanish 
480923c35297Sanish 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
481023c35297Sanish 
481123c35297Sanish 	range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
481223c35297Sanish 	    PCI_ADDR_IO);
481323c35297Sanish 	range[0].child_low = range[0].parent_low = io_base;
481423c35297Sanish 	range[1].child_high = range[1].parent_high |=
481523c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
481623c35297Sanish 	range[1].child_low = range[1].parent_low = mem_base;
481723c35297Sanish 	range[2].child_high = range[2].parent_high |=
481823c35297Sanish 	    (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
481923c35297Sanish 	range[2].child_low = range[2].parent_low = pf_mem_base;
482023c35297Sanish 
482123c35297Sanish 	if (io_size > 0) {
482223c35297Sanish 		range[0].size_low = io_size;
482323c35297Sanish 		(void) pcicfg_update_ranges_prop(new_child, &range[0]);
482423c35297Sanish 	}
482523c35297Sanish 	if (mem_size > 0) {
482623c35297Sanish 		range[1].size_low = mem_size;
482723c35297Sanish 		(void) pcicfg_update_ranges_prop(new_child, &range[1]);
482823c35297Sanish 	}
482923c35297Sanish 	if (pf_mem_size > 0) {
483023c35297Sanish 		range[2].size_low = pf_mem_size;
483123c35297Sanish 		(void) pcicfg_update_ranges_prop(new_child, &range[2]);
483223c35297Sanish 	}
483323c35297Sanish 
483423c35297Sanish 	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
483523c35297Sanish 	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
483623c35297Sanish 	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
483723c35297Sanish 	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
483823c35297Sanish 
483923c35297Sanish 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
484023c35297Sanish 	    "bus-range", bus_range, 2);
484123c35297Sanish 
484223c35297Sanish 	rval = PCICFG_SUCCESS;
484323c35297Sanish 
484423c35297Sanish 	PCICFG_DUMP_BRIDGE_CONFIG(h);
484523c35297Sanish 
484623c35297Sanish cleanup:
484723c35297Sanish 	/* free up resources (for error return case only) */
484823c35297Sanish 	if (rval != PCICFG_SUCCESS) {
484923c35297Sanish 		if (mem_alen)
485023c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
485123c35297Sanish 			    mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
485223c35297Sanish 		if (io_alen)
485323c35297Sanish 			(void) ndi_ra_free(ddi_get_parent(new_child), io_base,
485423c35297Sanish 			    io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
485523c35297Sanish 		if (pf_mem_alen)
485626947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child),
485726947304SEvan Yan 			    pf_mem_base, pf_mem_alen,
485826947304SEvan Yan 			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
485923c35297Sanish 		if (pcibus_alen)
486026947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child),
486126947304SEvan Yan 			    pcibus_base, pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM,
486226947304SEvan Yan 			    NDI_RA_PASS);
486323c35297Sanish 	}
486423c35297Sanish 
486523c35297Sanish 	/* free up any resource maps setup for the bridge node */
486623c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM);
486723c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO);
486823c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM);
486923c35297Sanish 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM);
487023c35297Sanish 
487123c35297Sanish 	return (rval);
487223c35297Sanish }
487323c35297Sanish 
487423c35297Sanish static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)487523c35297Sanish pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
487623c35297Sanish {
487723c35297Sanish 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
487823c35297Sanish 	pci_regspec_t *pci_ap;
487923c35297Sanish 	int length;
488023c35297Sanish 	int rcount;
488123c35297Sanish 	int i;
488223c35297Sanish 
488323c35297Sanish 	entry->error = PCICFG_SUCCESS;
488423c35297Sanish 
488523c35297Sanish 	if (dip == entry->dip) {
488623c35297Sanish 		DEBUG0("Don't include parent bridge node\n");
488723c35297Sanish 		return (DDI_WALK_CONTINUE);
488823c35297Sanish 	} else {
488923c35297Sanish 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
489023c35297Sanish 		    DDI_PROP_DONTPASS, "assigned-addresses",
489123c35297Sanish 		    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
489223c35297Sanish 			DEBUG0("Node doesn't have assigned-addresses\n");
489323c35297Sanish 			return (DDI_WALK_CONTINUE);
489423c35297Sanish 		}
489523c35297Sanish 
489623c35297Sanish 		rcount = length / sizeof (pci_regspec_t);
489723c35297Sanish 
489823c35297Sanish 		for (i = 0; i < rcount; i++) {
489923c35297Sanish 
490023c35297Sanish 			switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
490123c35297Sanish 
490223c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
490323c35297Sanish 				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
490423c35297Sanish 					if ((pci_ap[i].pci_phys_low +
490523c35297Sanish 					    pci_ap[i].pci_size_low) >
490623c35297Sanish 					    entry->pf_memory_base) {
490723c35297Sanish 						entry->pf_memory_base =
490823c35297Sanish 						    pci_ap[i].pci_phys_low +
490923c35297Sanish 						    pci_ap[i].pci_size_low;
491023c35297Sanish 					}
491123c35297Sanish 				} else {
491223c35297Sanish 					if ((pci_ap[i].pci_phys_low +
491323c35297Sanish 					    pci_ap[i].pci_size_low) >
491423c35297Sanish 					    entry->memory_base) {
491523c35297Sanish 						entry->memory_base =
491623c35297Sanish 						    pci_ap[i].pci_phys_low +
491723c35297Sanish 						    pci_ap[i].pci_size_low;
491823c35297Sanish 					}
491923c35297Sanish 				}
492023c35297Sanish 				break;
492123c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
492223c35297Sanish 				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
492326947304SEvan Yan 					if ((PCICFG_LADDR(
492426947304SEvan Yan 					    pci_ap[i].pci_phys_low,
492523c35297Sanish 					    pci_ap[i].pci_phys_mid) +
492623c35297Sanish 					    pci_ap[i].pci_size_low) >
492723c35297Sanish 					    entry->pf_memory_base) {
492826947304SEvan Yan 						entry->pf_memory_base =
492926947304SEvan Yan 						    PCICFG_LADDR(
493023c35297Sanish 						    pci_ap[i].pci_phys_low,
493123c35297Sanish 						    pci_ap[i].pci_phys_mid) +
493223c35297Sanish 						    pci_ap[i].pci_size_low;
493323c35297Sanish 					}
493423c35297Sanish 				} else {
493526947304SEvan Yan 					if ((PCICFG_LADDR(
493626947304SEvan Yan 					    pci_ap[i].pci_phys_low,
493723c35297Sanish 					    pci_ap[i].pci_phys_mid) +
493823c35297Sanish 					    pci_ap[i].pci_size_low) >
493923c35297Sanish 					    entry->memory_base) {
494026947304SEvan Yan 						entry->memory_base =
494126947304SEvan Yan 						    PCICFG_LADDR(
494223c35297Sanish 						    pci_ap[i].pci_phys_low,
494323c35297Sanish 						    pci_ap[i].pci_phys_mid) +
494423c35297Sanish 						    pci_ap[i].pci_size_low;
494523c35297Sanish 					}
494623c35297Sanish 				}
494723c35297Sanish 				break;
494823c35297Sanish 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
494923c35297Sanish 				if ((pci_ap[i].pci_phys_low +
495023c35297Sanish 				    pci_ap[i].pci_size_low) >
495123c35297Sanish 				    entry->io_base) {
495223c35297Sanish 					entry->io_base =
495323c35297Sanish 					    pci_ap[i].pci_phys_low +
495423c35297Sanish 					    pci_ap[i].pci_size_low;
495523c35297Sanish 				}
495623c35297Sanish 				break;
495723c35297Sanish 			}
495823c35297Sanish 		}
495923c35297Sanish 
496023c35297Sanish 		/*
496123c35297Sanish 		 * free the memory allocated by ddi_getlongprop
496223c35297Sanish 		 */
496323c35297Sanish 		kmem_free(pci_ap, length);
496423c35297Sanish 
496523c35297Sanish 		/*
496623c35297Sanish 		 * continue the walk to the next sibling to sum memory
496723c35297Sanish 		 */
496823c35297Sanish 		return (DDI_WALK_CONTINUE);
496923c35297Sanish 	}
497023c35297Sanish }
497123c35297Sanish 
497223c35297Sanish /*
497323c35297Sanish  * Make "parent" be the parent of the "child" dip
497423c35297Sanish  */
497523c35297Sanish static void
pcicfg_reparent_node(dev_info_t * child,dev_info_t * parent)497623c35297Sanish pcicfg_reparent_node(dev_info_t *child, dev_info_t *parent)
497723c35297Sanish {
497823c35297Sanish 	int circ;
497923c35297Sanish 	dev_info_t *opdip;
498023c35297Sanish 
498123c35297Sanish 	ASSERT(i_ddi_node_state(child) <= DS_LINKED);
498223c35297Sanish 	/*
498323c35297Sanish 	 * Unlink node from tree before reparenting
498423c35297Sanish 	 */
498523c35297Sanish 	opdip = ddi_get_parent(child);
498623c35297Sanish 	ndi_devi_enter(opdip, &circ);
498723c35297Sanish 	(void) i_ndi_unconfig_node(child, DS_PROTO, 0);
498823c35297Sanish 	ndi_devi_exit(opdip, circ);
498923c35297Sanish 
499023c35297Sanish 	DEVI(child)->devi_parent = DEVI(parent);
499123c35297Sanish 	DEVI(child)->devi_bus_ctl = DEVI(parent);
499223c35297Sanish 	(void) ndi_devi_bind_driver(child, 0);
499323c35297Sanish }
499423c35297Sanish 
499523c35297Sanish /*
499623c35297Sanish  * Return PCICFG_SUCCESS if device exists at the specified address.
499723c35297Sanish  * Return PCICFG_NODEVICE is no device exists at the specified address.
499823c35297Sanish  */
499923c35297Sanish int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)500023c35297Sanish pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
500123c35297Sanish {
500223c35297Sanish 	caddr_t	cfgaddr;
500323c35297Sanish 	ddi_device_acc_attr_t attr;
500423c35297Sanish 	dev_info_t *anode;
500523c35297Sanish 	int status;
500623c35297Sanish 	int		rlen;
500723c35297Sanish 	pci_regspec_t	*reg;
500823c35297Sanish 	int		ret = DDI_SUCCESS;
500923c35297Sanish 	int16_t		tmp;
501023c35297Sanish 
501123c35297Sanish 	/*
501223c35297Sanish 	 * Get the pci register spec from the node
501323c35297Sanish 	 */
501426947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
501526947304SEvan Yan 	    (caddr_t)&reg, &rlen);
501623c35297Sanish 
501723c35297Sanish 	switch (status) {
501823c35297Sanish 		case DDI_PROP_SUCCESS:
501923c35297Sanish 			break;
502023c35297Sanish 		case DDI_PROP_NO_MEMORY:
502123c35297Sanish 			DEBUG0("reg present, but unable to get memory\n");
502223c35297Sanish 			return (PCICFG_FAILURE);
502323c35297Sanish 		default:
502423c35297Sanish 			DEBUG0("no reg property\n");
502523c35297Sanish 			return (PCICFG_FAILURE);
502623c35297Sanish 	}
502723c35297Sanish 
502823c35297Sanish 	anode = dip;
502923c35297Sanish 	DEBUG2("conf_map: dip=%p, anode=%p\n", dip, anode);
503023c35297Sanish 
503123c35297Sanish 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
503223c35297Sanish 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
503323c35297Sanish 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
503423c35297Sanish 
503526947304SEvan Yan 	if (ddi_regs_map_setup(anode, 0, &cfgaddr, 0, 0, &attr, handle)
503626947304SEvan Yan 	    != DDI_SUCCESS) {
503723c35297Sanish 		DEBUG0("Failed to setup registers\n");
503823c35297Sanish 		kmem_free((caddr_t)reg, rlen);
503923c35297Sanish 		return (PCICFG_FAILURE);
504023c35297Sanish 	}
504123c35297Sanish 
504223c35297Sanish 	/*
504323c35297Sanish 	 * need to use DDI interfaces as the conf space is
504423c35297Sanish 	 * cannot be directly accessed by the host.
504523c35297Sanish 	 */
504623c35297Sanish 	tmp = (int16_t)ddi_get16(*handle, (uint16_t *)cfgaddr);
504723c35297Sanish 	if ((tmp == (int16_t)0xffff) || (tmp == -1)) {
504823c35297Sanish 		DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
504923c35297Sanish 		ret = PCICFG_NODEVICE;
505023c35297Sanish 	} else {
505123c35297Sanish 		if (tmp == 0) {
505223c35297Sanish 			DEBUG0("Device Not Ready yet ?");
505323c35297Sanish 			ret = PCICFG_NODEVICE;
505423c35297Sanish 		} else {
505523c35297Sanish 			DEBUG1("DEVICEFOUND, read %x\n", tmp);
505623c35297Sanish 			ret = PCICFG_SUCCESS;
505723c35297Sanish 		}
505823c35297Sanish 	}
505923c35297Sanish 
506023c35297Sanish 	if (ret == PCICFG_NODEVICE)
506123c35297Sanish 		ddi_regs_map_free(handle);
506223c35297Sanish 	kmem_free((caddr_t)reg, rlen);
506323c35297Sanish 
506423c35297Sanish 	return (ret);
506523c35297Sanish 
506623c35297Sanish }
506723c35297Sanish 
506823c35297Sanish static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)506923c35297Sanish pcicfg_config_teardown(ddi_acc_handle_t *handle)
507023c35297Sanish {
507123c35297Sanish 	(void) ddi_regs_map_free(handle);
507223c35297Sanish }
507323c35297Sanish 
507423c35297Sanish static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)507523c35297Sanish pcicfg_add_config_reg(dev_info_t *dip,
507623c35297Sanish 	uint_t bus, uint_t device, uint_t func)
507723c35297Sanish {
507823c35297Sanish 	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
507923c35297Sanish 
508023c35297Sanish 	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
508123c35297Sanish 
508226947304SEvan Yan 	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", reg, 5));
508323c35297Sanish }
508423c35297Sanish 
508526947304SEvan Yan static int
pcicfg_ari_configure(dev_info_t * dip)508626947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip)
508726947304SEvan Yan {
508826947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
508926947304SEvan Yan 		return (DDI_FAILURE);
509026947304SEvan Yan 
509126947304SEvan Yan 	/*
509226947304SEvan Yan 	 * Until we have resource balancing, dynamically configure
509326947304SEvan Yan 	 * ARI functions without firmware assistamce.
509426947304SEvan Yan 	 */
509526947304SEvan Yan 	return (DDI_FAILURE);
509626947304SEvan Yan }
509726947304SEvan Yan 
509826947304SEvan Yan 
509923c35297Sanish #ifdef DEBUG
510023c35297Sanish static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)510123c35297Sanish debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
510223c35297Sanish 	uintptr_t a4, uintptr_t a5)
510323c35297Sanish {
510423c35297Sanish 	if (pcicfg_debug > 1) {
510523c35297Sanish 		prom_printf("pcicfg: ");
510623c35297Sanish 		prom_printf(fmt, a1, a2, a3, a4, a5);
510723c35297Sanish 	}
510823c35297Sanish }
510923c35297Sanish #endif
511023c35297Sanish 
511123c35297Sanish /*ARGSUSED*/
511223c35297Sanish static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)511323c35297Sanish pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
511423c35297Sanish {
511549fbdd30SErwin T Tsaur 	uint16_t cap_id_loc, slot_id_loc;
511623c35297Sanish 	uint8_t num_slots = 0;
511723c35297Sanish 
511823c35297Sanish 	/* just depend on the pcie_cap for now. */
511949fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
512049fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &slot_id_loc);
512149fbdd30SErwin T Tsaur 	if (cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
512226947304SEvan Yan 		if (pci_config_get8(handle, cap_id_loc + PCI_CAP_ID_REGS_OFF) &
512323c35297Sanish 		    PCIE_PCIECAP_SLOT_IMPL)
512423c35297Sanish 			num_slots = 1;
512523c35297Sanish 	} else /* not a PCIe switch/bridge. Must be a PCI-PCI[-X] bridge */
512649fbdd30SErwin T Tsaur 	if (slot_id_loc != PCI_CAP_NEXT_PTR_NULL) {
512749fbdd30SErwin T Tsaur 		uint8_t esr_reg = pci_config_get8(handle, slot_id_loc + 2);
512823c35297Sanish 		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
512923c35297Sanish 	}
513023c35297Sanish 	/* XXX - need to cover PCI-PCIe bridge with n slots */
513123c35297Sanish 	return (num_slots);
513223c35297Sanish }
513323c35297Sanish 
513423c35297Sanish /*ARGSUSED*/
513523c35297Sanish static int
pcicfg_pcie_dev(dev_info_t * dip,ddi_acc_handle_t handle)513623c35297Sanish pcicfg_pcie_dev(dev_info_t *dip, ddi_acc_handle_t handle)
513723c35297Sanish {
513823c35297Sanish 	/* get parent device's device_type property */
513923c35297Sanish 	char *device_type;
514023c35297Sanish 	int val;
514123c35297Sanish 	dev_info_t *pdip = ddi_get_parent(dip);
514223c35297Sanish 
514326947304SEvan Yan 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
514426947304SEvan Yan 	    "device_type", &device_type) != DDI_PROP_SUCCESS) {
514523c35297Sanish 		DEBUG2("device_type property missing for %s#%d",
514623c35297Sanish 		    ddi_get_name(pdip), ddi_get_instance(pdip));
514723c35297Sanish 		return (DDI_FAILURE);
514823c35297Sanish 	}
514923c35297Sanish 	DEBUG1("device_type=<%s>\n", device_type);
515023c35297Sanish 
515123c35297Sanish 	val = DDI_FAILURE;
515223c35297Sanish 	if (strcmp(device_type, "pciex") == 0)
515323c35297Sanish 		val = DDI_SUCCESS;
515423c35297Sanish 	ddi_prop_free(device_type);
515523c35297Sanish 	return (val);
515623c35297Sanish }
515723c35297Sanish 
515823c35297Sanish static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)515923c35297Sanish pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
516023c35297Sanish {
516123c35297Sanish 	int port_type = pcicfg_pcie_port_type(dip, handle);
516223c35297Sanish 
516323c35297Sanish 	DEBUG1("device port_type = %x\n", port_type);
516423c35297Sanish 	/* No PCIe CAP regs, we are not PCIe device_type */
516523c35297Sanish 	if (port_type < 0)
516623c35297Sanish 		return (DDI_FAILURE);
516723c35297Sanish 
516823c35297Sanish 	/* check for all PCIe device_types */
516923c35297Sanish 	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
517023c35297Sanish 	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
517123c35297Sanish 	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
517223c35297Sanish 	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
517323c35297Sanish 		return (DDI_SUCCESS);
517423c35297Sanish 
517523c35297Sanish 	return (DDI_FAILURE);
517623c35297Sanish 
517723c35297Sanish }
517823c35297Sanish 
517923c35297Sanish /*ARGSUSED*/
518023c35297Sanish static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)518123c35297Sanish pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
518223c35297Sanish {
518323c35297Sanish 	int port_type = -1;
518449fbdd30SErwin T Tsaur 	uint16_t cap_loc;
518523c35297Sanish 
518623c35297Sanish 	/* Note: need to look at the port type information here */
518749fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_loc);
518849fbdd30SErwin T Tsaur 	if (cap_loc != PCI_CAP_NEXT_PTR_NULL)
518923c35297Sanish 		port_type = pci_config_get16(handle,
519023c35297Sanish 		    cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
519123c35297Sanish 
519223c35297Sanish 	return (port_type);
519323c35297Sanish }
5194c0da6274SZhi-Jun Robin Fu 
5195c0da6274SZhi-Jun Robin Fu /*
5196c0da6274SZhi-Jun Robin Fu  * Return true if the devinfo node is in a PCI Express hierarchy.
5197c0da6274SZhi-Jun Robin Fu  */
5198c0da6274SZhi-Jun Robin Fu static boolean_t
is_pcie_fabric(dev_info_t * dip)5199c0da6274SZhi-Jun Robin Fu is_pcie_fabric(dev_info_t *dip)
5200c0da6274SZhi-Jun Robin Fu {
5201c0da6274SZhi-Jun Robin Fu 	dev_info_t *root = ddi_root_node();
5202c0da6274SZhi-Jun Robin Fu 	dev_info_t *pdip;
5203c0da6274SZhi-Jun Robin Fu 	boolean_t found = B_FALSE;
5204c0da6274SZhi-Jun Robin Fu 	char *bus;
5205c0da6274SZhi-Jun Robin Fu 
5206c0da6274SZhi-Jun Robin Fu 	/*
5207c0da6274SZhi-Jun Robin Fu 	 * Does this device reside in a pcie fabric ?
5208c0da6274SZhi-Jun Robin Fu 	 */
5209c0da6274SZhi-Jun Robin Fu 	for (pdip = dip; pdip && (pdip != root) && !found;
5210c0da6274SZhi-Jun Robin Fu 	    pdip = ddi_get_parent(pdip)) {
5211c0da6274SZhi-Jun Robin Fu 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
5212c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_DONTPASS, "device_type", &bus) !=
5213c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_SUCCESS)
5214c0da6274SZhi-Jun Robin Fu 			break;
5215c0da6274SZhi-Jun Robin Fu 
5216c0da6274SZhi-Jun Robin Fu 		if (strcmp(bus, "pciex") == 0)
5217c0da6274SZhi-Jun Robin Fu 			found = B_TRUE;
5218c0da6274SZhi-Jun Robin Fu 
5219c0da6274SZhi-Jun Robin Fu 		ddi_prop_free(bus);
5220c0da6274SZhi-Jun Robin Fu 	}
5221c0da6274SZhi-Jun Robin Fu 
5222c0da6274SZhi-Jun Robin Fu 	return (found);
5223c0da6274SZhi-Jun Robin Fu }
5224