17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a6469d9bSprasad  * Common Development and Distribution License (the "License").
6a6469d9bSprasad  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227f59ab1cSAlan Adamson, SD OSSD  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23ffb64830SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
24b31f5cf7SDan Cross  * Copyright 2023 Oxide Computer Company
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  *     PCI configurator (pcicfg)
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
3170025d76Sjohnny #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/conf.h>
337c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
347c478bd9Sstevel@tonic-gate #include <sys/debug.h>
357c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
367c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
377c478bd9Sstevel@tonic-gate #include <sys/hwconf.h>
3870025d76Sjohnny #include <sys/pcie.h>
3926947304SEvan Yan #include <sys/pcie_impl.h>
4049fbdd30SErwin T Tsaur #include <sys/pci_cap.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
437c478bd9Sstevel@tonic-gate #include <sys/hotplug/pci/pcicfg.h>
447c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
45c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
46*bd97c7ceSRobert Mustacchi #include <sys/pci_props.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * ************************************************************************
507c478bd9Sstevel@tonic-gate  * *** Implementation specific local data structures/definitions.	***
517c478bd9Sstevel@tonic-gate  * ************************************************************************
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static	int	pcicfg_start_devno = 0;	/* for Debug only */
557c478bd9Sstevel@tonic-gate 
5626947304SEvan Yan #define	PCICFG_MAX_ARI_FUNCTION 256
5726947304SEvan Yan 
587c478bd9Sstevel@tonic-gate #define	PCICFG_NODEVICE 42
597c478bd9Sstevel@tonic-gate #define	PCICFG_NOMEMORY 43
607c478bd9Sstevel@tonic-gate #define	PCICFG_NOMULTI	44
615af4ae46Sjveta #define	PCICFG_NORESRC	45
627c478bd9Sstevel@tonic-gate 
63a6469d9bSprasad #define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & \
64a6469d9bSprasad 	0xFFFFFFFF00000000ULL)>> 32))
657c478bd9Sstevel@tonic-gate #define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
667c478bd9Sstevel@tonic-gate #define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
697c478bd9Sstevel@tonic-gate #define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
707c478bd9Sstevel@tonic-gate #define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
717c478bd9Sstevel@tonic-gate #define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
747c478bd9Sstevel@tonic-gate #define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #define	PCICFG_MEMGRAN 0x100000
777c478bd9Sstevel@tonic-gate #define	PCICFG_IOGRAN 0x1000
787c478bd9Sstevel@tonic-gate #define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #define	PCICFG_MEM_MULT 4
817c478bd9Sstevel@tonic-gate #define	PCICFG_IO_MULT 4
82a6469d9bSprasad #define	PCICFG_RANGE_LEN 3 /* Number of range entries */
837c478bd9Sstevel@tonic-gate 
8470025d76Sjohnny static int pcicfg_slot_busnums = 8;
8570025d76Sjohnny static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
86a6469d9bSprasad static int pcicfg_slot_pf_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8770025d76Sjohnny static int pcicfg_slot_iosize = 64 * PCICFG_IOGRAN; /* 64K per slot */
8870025d76Sjohnny static int pcicfg_sec_reset_delay = 3000000;
8970025d76Sjohnny 
907c478bd9Sstevel@tonic-gate typedef struct hole hole_t;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate struct hole {
937c478bd9Sstevel@tonic-gate 	uint64_t	start;
947c478bd9Sstevel@tonic-gate 	uint64_t	len;
957c478bd9Sstevel@tonic-gate 	hole_t		*next;
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate typedef struct pcicfg_phdl pcicfg_phdl_t;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate struct pcicfg_phdl {
1017c478bd9Sstevel@tonic-gate 
10270025d76Sjohnny 	dev_info_t	*dip;		/* Associated with the bridge */
10370025d76Sjohnny 	dev_info_t	*top_dip;	/* top node of the attach point */
1047c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t	*next;
1057c478bd9Sstevel@tonic-gate 
106a6469d9bSprasad 	/* non-prefetchable memory space */
1077c478bd9Sstevel@tonic-gate 	uint64_t	memory_base;	/* Memory base for this attach point */
1087c478bd9Sstevel@tonic-gate 	uint64_t	memory_last;
1097c478bd9Sstevel@tonic-gate 	uint64_t	memory_len;
110a6469d9bSprasad 
111a6469d9bSprasad 	/* prefetchable memory space */
11226947304SEvan Yan 	uint64_t	pf_memory_base;	/* PF Memory base for this Connection */
113a6469d9bSprasad 	uint64_t	pf_memory_last;
114a6469d9bSprasad 	uint64_t	pf_memory_len;
115a6469d9bSprasad 
116a6469d9bSprasad 	/* io space */
1177c478bd9Sstevel@tonic-gate 	uint32_t	io_base;	/* I/O base for this attach point */
1187c478bd9Sstevel@tonic-gate 	uint32_t	io_last;
1197c478bd9Sstevel@tonic-gate 	uint32_t	io_len;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	int		error;
1227c478bd9Sstevel@tonic-gate 	uint_t		highest_bus;	/* Highest bus seen on the probe */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	hole_t		mem_hole;	/* Memory hole linked list. */
125a6469d9bSprasad 	hole_t		pf_mem_hole;	/* PF Memory hole linked list. */
1267c478bd9Sstevel@tonic-gate 	hole_t		io_hole;	/* IO hole linked list */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	ndi_ra_request_t mem_req;	/* allocator request for memory */
129a6469d9bSprasad 	ndi_ra_request_t pf_mem_req;	/* allocator request for PF memory */
1307c478bd9Sstevel@tonic-gate 	ndi_ra_request_t io_req;	/* allocator request for I/O */
1317c478bd9Sstevel@tonic-gate };
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate struct pcicfg_standard_prop_entry {
1347c478bd9Sstevel@tonic-gate     uchar_t *name;
1357c478bd9Sstevel@tonic-gate     uint_t  config_offset;
1367c478bd9Sstevel@tonic-gate     uint_t  size;
1377c478bd9Sstevel@tonic-gate };
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate struct pcicfg_name_entry {
1417c478bd9Sstevel@tonic-gate     uint32_t class_code;
1427c478bd9Sstevel@tonic-gate     char  *name;
1437c478bd9Sstevel@tonic-gate };
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate struct pcicfg_find_ctrl {
1467c478bd9Sstevel@tonic-gate 	uint_t		device;
1477c478bd9Sstevel@tonic-gate 	uint_t		function;
1487c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
1497c478bd9Sstevel@tonic-gate };
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * List of Indirect Config Map Devices. At least the intent of the
1537c478bd9Sstevel@tonic-gate  * design is to look for a device in this list during the configure
1547c478bd9Sstevel@tonic-gate  * operation, and if the device is listed here, then it is a nontransparent
1557c478bd9Sstevel@tonic-gate  * bridge, hence load the driver and avail the config map services from
1567c478bd9Sstevel@tonic-gate  * the driver. Class and Subclass should be as defined in the PCI specs
1577c478bd9Sstevel@tonic-gate  * ie. class is 0x6, and subclass is 0x9.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static struct {
1607c478bd9Sstevel@tonic-gate 	uint8_t		mem_range_bar_offset;
1617c478bd9Sstevel@tonic-gate 	uint8_t		io_range_bar_offset;
1627c478bd9Sstevel@tonic-gate 	uint8_t		prefetch_mem_range_bar_offset;
1637c478bd9Sstevel@tonic-gate } pcicfg_indirect_map_devs[] = {
1647c478bd9Sstevel@tonic-gate 	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
1657c478bd9Sstevel@tonic-gate 	0,	0,	0,
1667c478bd9Sstevel@tonic-gate };
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate #define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
1697c478bd9Sstevel@tonic-gate 	(\
1707c478bd9Sstevel@tonic-gate 	((ulong_t)(busnum & 0xff) << 16)    |\
1717c478bd9Sstevel@tonic-gate 	((ulong_t)(devnum & 0x1f) << 11)    |\
1727c478bd9Sstevel@tonic-gate 	((ulong_t)(funcnum & 0x7) <<  8)    |\
1737c478bd9Sstevel@tonic-gate 	((ulong_t)(register & 0x3f)))
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate  * debug macros:
1777c478bd9Sstevel@tonic-gate  */
1787c478bd9Sstevel@tonic-gate #if	defined(DEBUG)
1797c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * Following values are defined for this debug flag.
1837c478bd9Sstevel@tonic-gate  *
1847c478bd9Sstevel@tonic-gate  * 1 = dump configuration header only.
1857c478bd9Sstevel@tonic-gate  * 2 = dump generic debug data only (no config header dumped)
1867c478bd9Sstevel@tonic-gate  * 3 = dump everything (both 1 and 2)
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate int pcicfg_debug = 0;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate static void debug(char *, uintptr_t, uintptr_t,
1917c478bd9Sstevel@tonic-gate 	uintptr_t, uintptr_t, uintptr_t);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate #define	DEBUG0(fmt)\
1947c478bd9Sstevel@tonic-gate 	debug(fmt, 0, 0, 0, 0, 0);
1957c478bd9Sstevel@tonic-gate #define	DEBUG1(fmt, a1)\
1967c478bd9Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
1977c478bd9Sstevel@tonic-gate #define	DEBUG2(fmt, a1, a2)\
1987c478bd9Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
1997c478bd9Sstevel@tonic-gate #define	DEBUG3(fmt, a1, a2, a3)\
2007c478bd9Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
2017c478bd9Sstevel@tonic-gate 		(uintptr_t)(a3), 0, 0);
2027c478bd9Sstevel@tonic-gate #define	DEBUG4(fmt, a1, a2, a3, a4)\
2037c478bd9Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
2047c478bd9Sstevel@tonic-gate 		(uintptr_t)(a3), (uintptr_t)(a4), 0);
205a6469d9bSprasad #define	DEBUG5(fmt, a1, a2, a3, a4, a5)\
206a6469d9bSprasad 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
207a6469d9bSprasad 		(uintptr_t)(a3), (uintptr_t)(a4), (uintptr_t)(a5));
2087c478bd9Sstevel@tonic-gate #else
2097c478bd9Sstevel@tonic-gate #define	DEBUG0(fmt)
2107c478bd9Sstevel@tonic-gate #define	DEBUG1(fmt, a1)
2117c478bd9Sstevel@tonic-gate #define	DEBUG2(fmt, a1, a2)
2127c478bd9Sstevel@tonic-gate #define	DEBUG3(fmt, a1, a2, a3)
2137c478bd9Sstevel@tonic-gate #define	DEBUG4(fmt, a1, a2, a3, a4)
214a6469d9bSprasad #define	DEBUG5(fmt, a1, a2, a3, a4, a5)
2157c478bd9Sstevel@tonic-gate #endif
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate /*
2187c478bd9Sstevel@tonic-gate  * forward declarations for routines defined in this module (called here)
2197c478bd9Sstevel@tonic-gate  */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate static int pcicfg_add_config_reg(dev_info_t *,
22226947304SEvan Yan     uint_t, uint_t, uint_t);
22370025d76Sjohnny static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
224c0da6274SZhi-Jun Robin Fu     uint_t *, pcicfg_flags_t, boolean_t);
2257c478bd9Sstevel@tonic-gate static int pcicfg_match_dev(dev_info_t *, void *);
2267c478bd9Sstevel@tonic-gate static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
2277c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
2287c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
2297c478bd9Sstevel@tonic-gate static int pcicfg_destroy_phdl(dev_info_t *);
2307c478bd9Sstevel@tonic-gate static int pcicfg_sum_resources(dev_info_t *, void *);
2317c478bd9Sstevel@tonic-gate static int pcicfg_device_assign(dev_info_t *);
2327c478bd9Sstevel@tonic-gate static int pcicfg_bridge_assign(dev_info_t *, void *);
23326947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *);
23426947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
2357c478bd9Sstevel@tonic-gate static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
2367c478bd9Sstevel@tonic-gate static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
2377c478bd9Sstevel@tonic-gate static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
2387c478bd9Sstevel@tonic-gate static void pcicfg_device_on(ddi_acc_handle_t);
2397c478bd9Sstevel@tonic-gate static void pcicfg_device_off(ddi_acc_handle_t);
24070025d76Sjohnny static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
2417c478bd9Sstevel@tonic-gate static int pcicfg_free_bridge_resources(dev_info_t *);
2427c478bd9Sstevel@tonic-gate static int pcicfg_free_device_resources(dev_info_t *);
243c0da6274SZhi-Jun Robin Fu static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
2447c478bd9Sstevel@tonic-gate static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
2457c478bd9Sstevel@tonic-gate static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
2467c478bd9Sstevel@tonic-gate static void pcicfg_config_teardown(ddi_acc_handle_t *);
2477c478bd9Sstevel@tonic-gate static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
248a6469d9bSprasad static void pcicfg_get_pf_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
2497c478bd9Sstevel@tonic-gate static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
25000d0963fSdilpreet static int pcicfg_update_ranges_prop(dev_info_t *, ppb_ranges_t *);
25170025d76Sjohnny static int pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
2527c478bd9Sstevel@tonic-gate static uint_t pcicfg_ntbridge_child(dev_info_t *);
2537c478bd9Sstevel@tonic-gate static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
25426947304SEvan Yan     uint64_t *, uint_t);
2557c478bd9Sstevel@tonic-gate static int pcicfg_is_ntbridge(dev_info_t *);
2567c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
2577c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_configure_done(dev_info_t *);
2587c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_program_child(dev_info_t *);
2597c478bd9Sstevel@tonic-gate static uint_t pcicfg_ntbridge_unconfigure(dev_info_t *);
2607c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
2617c478bd9Sstevel@tonic-gate static void pcicfg_free_hole(hole_t *);
2627c478bd9Sstevel@tonic-gate static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
26370025d76Sjohnny static int pcicfg_device_type(dev_info_t *, ddi_acc_handle_t *);
26470025d76Sjohnny static void pcicfg_update_phdl(dev_info_t *, uint8_t, uint8_t);
26570025d76Sjohnny static int pcicfg_get_cap(ddi_acc_handle_t, uint8_t);
26670025d76Sjohnny static uint8_t pcicfg_get_nslots(dev_info_t *, ddi_acc_handle_t);
26770025d76Sjohnny static int pcicfg_pcie_device_type(dev_info_t *, ddi_acc_handle_t);
26870025d76Sjohnny static int pcicfg_pcie_port_type(dev_info_t *, ddi_acc_handle_t);
26970025d76Sjohnny static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
270c0da6274SZhi-Jun Robin Fu 	uint_t *, boolean_t);
27170025d76Sjohnny static int pcicfg_find_resource_end(dev_info_t *, void *);
272c0da6274SZhi-Jun Robin Fu static boolean_t is_pcie_fabric(dev_info_t *);
2737c478bd9Sstevel@tonic-gate 
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 
2807c478bd9Sstevel@tonic-gate #ifdef DEBUG
2817c478bd9Sstevel@tonic-gate static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
2827c478bd9Sstevel@tonic-gate static void pcicfg_dump_device_config(ddi_acc_handle_t);
2837c478bd9Sstevel@tonic-gate static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
2847c478bd9Sstevel@tonic-gate static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate #define	PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
2877c478bd9Sstevel@tonic-gate #define	PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
2887c478bd9Sstevel@tonic-gate #define	PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
2897c478bd9Sstevel@tonic-gate #else
2907c478bd9Sstevel@tonic-gate #define	PCICFG_DUMP_COMMON_CONFIG(handle)
2917c478bd9Sstevel@tonic-gate #define	PCICFG_DUMP_DEVICE_CONFIG(handle)
2927c478bd9Sstevel@tonic-gate #define	PCICFG_DUMP_BRIDGE_CONFIG(handle)
2937c478bd9Sstevel@tonic-gate #endif
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
2967c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate #ifndef _DONT_USE_1275_GENERIC_NAMES
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  * Class code table
3017c478bd9Sstevel@tonic-gate  */
3027c478bd9Sstevel@tonic-gate static struct pcicfg_name_entry pcicfg_class_lookup [] = {
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	{ 0x001, "display" },
3057c478bd9Sstevel@tonic-gate 	{ 0x100, "scsi" },
3067c478bd9Sstevel@tonic-gate 	{ 0x101, "ide" },
3077c478bd9Sstevel@tonic-gate 	{ 0x102, "fdc" },
3087c478bd9Sstevel@tonic-gate 	{ 0x103, "ipi" },
3097c478bd9Sstevel@tonic-gate 	{ 0x104, "raid" },
31070025d76Sjohnny 	{ 0x105, "ata" },
31170025d76Sjohnny 	{ 0x106, "sata" },
3127c478bd9Sstevel@tonic-gate 	{ 0x200, "ethernet" },
3137c478bd9Sstevel@tonic-gate 	{ 0x201, "token-ring" },
3147c478bd9Sstevel@tonic-gate 	{ 0x202, "fddi" },
3157c478bd9Sstevel@tonic-gate 	{ 0x203, "atm" },
31670025d76Sjohnny 	{ 0x204, "isdn" },
31770025d76Sjohnny 	{ 0x206, "mcd" },
3187c478bd9Sstevel@tonic-gate 	{ 0x300, "display" },
3197c478bd9Sstevel@tonic-gate 	{ 0x400, "video" },
3207c478bd9Sstevel@tonic-gate 	{ 0x401, "sound" },
3217c478bd9Sstevel@tonic-gate 	{ 0x500, "memory" },
3227c478bd9Sstevel@tonic-gate 	{ 0x501, "flash" },
3237c478bd9Sstevel@tonic-gate 	{ 0x600, "host" },
3247c478bd9Sstevel@tonic-gate 	{ 0x601, "isa" },
3257c478bd9Sstevel@tonic-gate 	{ 0x602, "eisa" },
3267c478bd9Sstevel@tonic-gate 	{ 0x603, "mca" },
3277c478bd9Sstevel@tonic-gate 	{ 0x604, "pci" },
3287c478bd9Sstevel@tonic-gate 	{ 0x605, "pcmcia" },
3297c478bd9Sstevel@tonic-gate 	{ 0x606, "nubus" },
3307c478bd9Sstevel@tonic-gate 	{ 0x607, "cardbus" },
3317c478bd9Sstevel@tonic-gate 	{ 0x609, "pci" },
33270025d76Sjohnny 	{ 0x60a, "ib-pci" },
3337c478bd9Sstevel@tonic-gate 	{ 0x700, "serial" },
3347c478bd9Sstevel@tonic-gate 	{ 0x701, "parallel" },
3357c478bd9Sstevel@tonic-gate 	{ 0x800, "interrupt-controller" },
3367c478bd9Sstevel@tonic-gate 	{ 0x801, "dma-controller" },
3377c478bd9Sstevel@tonic-gate 	{ 0x802, "timer" },
3387c478bd9Sstevel@tonic-gate 	{ 0x803, "rtc" },
3397c478bd9Sstevel@tonic-gate 	{ 0x900, "keyboard" },
3407c478bd9Sstevel@tonic-gate 	{ 0x901, "pen" },
3417c478bd9Sstevel@tonic-gate 	{ 0x902, "mouse" },
3427c478bd9Sstevel@tonic-gate 	{ 0xa00, "dock" },
3437c478bd9Sstevel@tonic-gate 	{ 0xb00, "cpu" },
34470025d76Sjohnny 	{ 0xb01, "cpu" },
34570025d76Sjohnny 	{ 0xb02, "cpu" },
34670025d76Sjohnny 	{ 0xb10, "cpu" },
34770025d76Sjohnny 	{ 0xb20, "cpu" },
34870025d76Sjohnny 	{ 0xb30, "cpu" },
34970025d76Sjohnny 	{ 0xb40, "coproc" },
3507c478bd9Sstevel@tonic-gate 	{ 0xc00, "firewire" },
3517c478bd9Sstevel@tonic-gate 	{ 0xc01, "access-bus" },
3527c478bd9Sstevel@tonic-gate 	{ 0xc02, "ssa" },
3537c478bd9Sstevel@tonic-gate 	{ 0xc03, "usb" },
3547c478bd9Sstevel@tonic-gate 	{ 0xc04, "fibre-channel" },
35570025d76Sjohnny 	{ 0xc05, "smbus" },
35670025d76Sjohnny 	{ 0xc06, "ib" },
35770025d76Sjohnny 	{ 0xd00, "irda" },
35870025d76Sjohnny 	{ 0xd01, "ir" },
35970025d76Sjohnny 	{ 0xd10, "rf" },
36070025d76Sjohnny 	{ 0xd11, "btooth" },
36170025d76Sjohnny 	{ 0xd12, "brdband" },
36270025d76Sjohnny 	{ 0xd20, "802.11a" },
36370025d76Sjohnny 	{ 0xd21, "802.11b" },
36470025d76Sjohnny 	{ 0xe00, "i2o" },
36570025d76Sjohnny 	{ 0xf01, "tv" },
36670025d76Sjohnny 	{ 0xf02, "audio" },
36770025d76Sjohnny 	{ 0xf03, "voice" },
36870025d76Sjohnny 	{ 0xf04, "data" },
3697c478bd9Sstevel@tonic-gate 	{ 0, 0 }
3707c478bd9Sstevel@tonic-gate };
3717c478bd9Sstevel@tonic-gate #endif /* _DONT_USE_1275_GENERIC_NAMES */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate /*
3747c478bd9Sstevel@tonic-gate  * Module control operations
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
3807c478bd9Sstevel@tonic-gate 	&mod_miscops, /* Type of module */
381613b2871SRichard Bean 	"PCI configurator"
3827c478bd9Sstevel@tonic-gate };
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
3857c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
3867c478bd9Sstevel@tonic-gate };
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate #ifdef DEBUG
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate static void
pcicfg_dump_common_config(ddi_acc_handle_t config_handle)3927c478bd9Sstevel@tonic-gate pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	if ((pcicfg_debug & 1) == 0)
3957c478bd9Sstevel@tonic-gate 		return;
3967c478bd9Sstevel@tonic-gate 	prom_printf(" Vendor ID   = [0x%x]\n",
39726947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID));
3987c478bd9Sstevel@tonic-gate 	prom_printf(" Device ID   = [0x%x]\n",
39926947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
4007c478bd9Sstevel@tonic-gate 	prom_printf(" Command REG = [0x%x]\n",
40126947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_COMM));
4027c478bd9Sstevel@tonic-gate 	prom_printf(" Status  REG = [0x%x]\n",
40326947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_STAT));
4047c478bd9Sstevel@tonic-gate 	prom_printf(" Revision ID = [0x%x]\n",
40526947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_REVID));
4067c478bd9Sstevel@tonic-gate 	prom_printf(" Prog Class  = [0x%x]\n",
40726947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
4087c478bd9Sstevel@tonic-gate 	prom_printf(" Dev Class   = [0x%x]\n",
40926947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
4107c478bd9Sstevel@tonic-gate 	prom_printf(" Base Class  = [0x%x]\n",
41126947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
4127c478bd9Sstevel@tonic-gate 	prom_printf(" Device ID   = [0x%x]\n",
41326947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
4147c478bd9Sstevel@tonic-gate 	prom_printf(" Header Type = [0x%x]\n",
41526947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_HEADER));
4167c478bd9Sstevel@tonic-gate 	prom_printf(" BIST        = [0x%x]\n",
41726947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_BIST));
4187c478bd9Sstevel@tonic-gate 	prom_printf(" BASE 0      = [0x%x]\n",
41926947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE0));
4207c478bd9Sstevel@tonic-gate 	prom_printf(" BASE 1      = [0x%x]\n",
42126947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE1));
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate static void
pcicfg_dump_device_config(ddi_acc_handle_t config_handle)4267c478bd9Sstevel@tonic-gate pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	if ((pcicfg_debug & 1) == 0)
4297c478bd9Sstevel@tonic-gate 		return;
4307c478bd9Sstevel@tonic-gate 	pcicfg_dump_common_config(config_handle);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	prom_printf(" BASE 2      = [0x%x]\n",
43326947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE2));
4347c478bd9Sstevel@tonic-gate 	prom_printf(" BASE 3      = [0x%x]\n",
43526947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE3));
4367c478bd9Sstevel@tonic-gate 	prom_printf(" BASE 4      = [0x%x]\n",
43726947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE4));
4387c478bd9Sstevel@tonic-gate 	prom_printf(" BASE 5      = [0x%x]\n",
43926947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_BASE5));
4407c478bd9Sstevel@tonic-gate 	prom_printf(" Cardbus CIS = [0x%x]\n",
44126947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_CIS));
4427c478bd9Sstevel@tonic-gate 	prom_printf(" Sub VID     = [0x%x]\n",
44326947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
4447c478bd9Sstevel@tonic-gate 	prom_printf(" Sub SID     = [0x%x]\n",
44526947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
4467c478bd9Sstevel@tonic-gate 	prom_printf(" ROM         = [0x%x]\n",
44726947304SEvan Yan 	    pci_config_get32(config_handle, PCI_CONF_ROM));
4487c478bd9Sstevel@tonic-gate 	prom_printf(" I Line      = [0x%x]\n",
44926947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_ILINE));
4507c478bd9Sstevel@tonic-gate 	prom_printf(" I Pin       = [0x%x]\n",
45126947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_IPIN));
4527c478bd9Sstevel@tonic-gate 	prom_printf(" Max Grant   = [0x%x]\n",
45326947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
4547c478bd9Sstevel@tonic-gate 	prom_printf(" Max Latent  = [0x%x]\n",
45526947304SEvan Yan 	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate static void
pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)4597c478bd9Sstevel@tonic-gate pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	if ((pcicfg_debug & 1) == 0)
4627c478bd9Sstevel@tonic-gate 		return;
4637c478bd9Sstevel@tonic-gate 	pcicfg_dump_common_config(config_handle);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	prom_printf("........................................\n");
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	prom_printf(" Pri Bus     = [0x%x]\n",
46826947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
4697c478bd9Sstevel@tonic-gate 	prom_printf(" Sec Bus     = [0x%x]\n",
47026947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
4717c478bd9Sstevel@tonic-gate 	prom_printf(" Sub Bus     = [0x%x]\n",
47226947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
4737c478bd9Sstevel@tonic-gate 	prom_printf(" Latency     = [0x%x]\n",
47426947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
4757c478bd9Sstevel@tonic-gate 	prom_printf(" I/O Base LO = [0x%x]\n",
47626947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
4777c478bd9Sstevel@tonic-gate 	prom_printf(" I/O Lim LO  = [0x%x]\n",
47826947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
4797c478bd9Sstevel@tonic-gate 	prom_printf(" Sec. Status = [0x%x]\n",
48026947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
4817c478bd9Sstevel@tonic-gate 	prom_printf(" Mem Base    = [0x%x]\n",
48226947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
4837c478bd9Sstevel@tonic-gate 	prom_printf(" Mem Limit   = [0x%x]\n",
48426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
4857c478bd9Sstevel@tonic-gate 	prom_printf(" PF Mem Base = [0x%x]\n",
48626947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
4877c478bd9Sstevel@tonic-gate 	prom_printf(" PF Mem Lim  = [0x%x]\n",
48826947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
4897c478bd9Sstevel@tonic-gate 	prom_printf(" PF Base HI  = [0x%x]\n",
49026947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
4917c478bd9Sstevel@tonic-gate 	prom_printf(" PF Lim  HI  = [0x%x]\n",
49226947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
4937c478bd9Sstevel@tonic-gate 	prom_printf(" I/O Base HI = [0x%x]\n",
49426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
4957c478bd9Sstevel@tonic-gate 	prom_printf(" I/O Lim HI  = [0x%x]\n",
49626947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
4977c478bd9Sstevel@tonic-gate 	prom_printf(" ROM addr    = [0x%x]\n",
49826947304SEvan Yan 	    pci_config_get32(config_handle, PCI_BCNF_ROM));
4997c478bd9Sstevel@tonic-gate 	prom_printf(" Intr Line   = [0x%x]\n",
50026947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
5017c478bd9Sstevel@tonic-gate 	prom_printf(" Intr Pin    = [0x%x]\n",
50226947304SEvan Yan 	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
5037c478bd9Sstevel@tonic-gate 	prom_printf(" Bridge Ctrl = [0x%x]\n",
50426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate #endif
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate int
_init()5097c478bd9Sstevel@tonic-gate _init()
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	DEBUG0(" PCI configurator installed\n");
5127c478bd9Sstevel@tonic-gate 	mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
5137c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate int
_fini(void)5177c478bd9Sstevel@tonic-gate _fini(void)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	int error;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	error = mod_remove(&modlinkage);
5227c478bd9Sstevel@tonic-gate 	if (error != 0) {
5237c478bd9Sstevel@tonic-gate 		return (error);
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 	mutex_destroy(&pcicfg_list_mutex);
5267c478bd9Sstevel@tonic-gate 	return (0);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)5307c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate  * In the following functions ndi_devi_enter() without holding the
5377c478bd9Sstevel@tonic-gate  * parent dip is sufficient. This is because  pci dr is driven through
5387c478bd9Sstevel@tonic-gate  * opens on the nexus which is in the device tree path above the node
5397c478bd9Sstevel@tonic-gate  * being operated on, and implicitly held due to the open.
5407c478bd9Sstevel@tonic-gate  */
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate  * This entry point is called to configure a device (and
5447c478bd9Sstevel@tonic-gate  * all its children) on the given bus. It is called when
5457c478bd9Sstevel@tonic-gate  * a new device is added to the PCI domain.  This routine
5467c478bd9Sstevel@tonic-gate  * will create the device tree and program the devices
5477c478bd9Sstevel@tonic-gate  * registers.
5487c478bd9Sstevel@tonic-gate  */
5497c478bd9Sstevel@tonic-gate 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)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	uint_t bus;
5547c478bd9Sstevel@tonic-gate 	int len;
5557c478bd9Sstevel@tonic-gate 	int func;
5567c478bd9Sstevel@tonic-gate 	dev_info_t *attach_point;
55700d0963fSdilpreet 	pci_bus_range_t pci_bus_range;
5587c478bd9Sstevel@tonic-gate 	int rv;
5595c734816SRobert Mustacchi 	uint_t highest_bus, visited = 0;
56026947304SEvan Yan 	int ari_mode = B_FALSE;
56126947304SEvan Yan 	int max_function = PCI_MAX_FUNCTIONS;
56226947304SEvan Yan 	int trans_device;
56326947304SEvan Yan 	dev_info_t *new_device;
564c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
56526947304SEvan Yan 
56626947304SEvan Yan 	if (flags == PCICFG_FLAG_ENABLE_ARI)
56726947304SEvan Yan 		return (pcicfg_ari_configure(devi));
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	/*
5707c478bd9Sstevel@tonic-gate 	 * Start probing at the device specified in "device" on the
5717c478bd9Sstevel@tonic-gate 	 * "bus" specified.
5727c478bd9Sstevel@tonic-gate 	 */
57300d0963fSdilpreet 	len = sizeof (pci_bus_range_t);
574a3282898Scth 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, 0, "bus-range",
5757c478bd9Sstevel@tonic-gate 	    (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
5767c478bd9Sstevel@tonic-gate 		DEBUG0("no bus-range property\n");
5777c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
5817c478bd9Sstevel@tonic-gate 
58270025d76Sjohnny 	attach_point = devi;
5837c478bd9Sstevel@tonic-gate 
584c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
585c0da6274SZhi-Jun Robin Fu 
586b31f5cf7SDan Cross 	/*
587b31f5cf7SDan Cross 	 * This code may be racing against other code walking the device info
588b31f5cf7SDan Cross 	 * tree, such as `di_copytree` et al.  To avoid deadlock, we must ensure
589b31f5cf7SDan Cross 	 * a strict hierarchical ordering of `ndi_devi_enter` calls that mirrors
590b31f5cf7SDan Cross 	 * the structure of the tree, working from the root towards leaves.
591b31f5cf7SDan Cross 	 * `pcie_fabric_setup`, if called, will call `ddi_walk_devs` which
592b31f5cf7SDan Cross 	 * requires that the parent is locked; therefore, to obey the lock
593b31f5cf7SDan Cross 	 * ordering, we must lock the parent here.
594b31f5cf7SDan Cross 	 */
5953fe80ca4SDan Cross 	ndi_devi_enter(ddi_get_parent(devi));
5963fe80ca4SDan Cross 	ndi_devi_enter(devi);
59726947304SEvan Yan 	for (func = 0; func < max_function; ) {
5987c478bd9Sstevel@tonic-gate 
59926947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
60026947304SEvan Yan 			goto next;
60126947304SEvan Yan 
60226947304SEvan Yan 		if (ari_mode)
60326947304SEvan Yan 			trans_device = func >> 3;
60426947304SEvan Yan 		else
60526947304SEvan Yan 			trans_device = device;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 		switch (rv = pcicfg_probe_children(attach_point,
608c0da6274SZhi-Jun Robin Fu 		    bus, trans_device, func & 7, &highest_bus,
609c0da6274SZhi-Jun Robin Fu 		    flags, is_pcie)) {
6105af4ae46Sjveta 			case PCICFG_NORESRC:
6117c478bd9Sstevel@tonic-gate 			case PCICFG_FAILURE:
61226947304SEvan Yan 				DEBUG2("configure failed: bus [0x%x] device "
61326947304SEvan Yan 				    "[0x%x]\n", bus, trans_device);
6147c478bd9Sstevel@tonic-gate 				goto cleanup;
6157c478bd9Sstevel@tonic-gate 			case PCICFG_NODEVICE:
6167c478bd9Sstevel@tonic-gate 				DEBUG3("no device : bus "
61726947304SEvan Yan 				    "[0x%x] slot [0x%x] func [0x%x]\n",
61826947304SEvan Yan 				    bus, trans_device, func &7);
61926947304SEvan Yan 
6207f59ab1cSAlan Adamson, SD OSSD 				/*
6217f59ab1cSAlan Adamson, SD OSSD 				 * When walking the list of ARI functions
6227f59ab1cSAlan Adamson, SD OSSD 				 * we don't expect to see a non-present
6237f59ab1cSAlan Adamson, SD OSSD 				 * function, so we will stop walking
6247f59ab1cSAlan Adamson, SD OSSD 				 * the function list.
6257f59ab1cSAlan Adamson, SD OSSD 				 */
6267f59ab1cSAlan Adamson, SD OSSD 				if (ari_mode == B_TRUE)
6277f59ab1cSAlan Adamson, SD OSSD 					break;
6287f59ab1cSAlan Adamson, SD OSSD 
62926947304SEvan Yan 				if (func)
63026947304SEvan Yan 					goto next;
63126947304SEvan Yan 				break;
6327c478bd9Sstevel@tonic-gate 			default:
6337c478bd9Sstevel@tonic-gate 				DEBUG3("configure: bus => [%d] "
63426947304SEvan Yan 				    "slot => [%d] func => [%d]\n",
63526947304SEvan Yan 				    bus, trans_device, func & 7);
6367c478bd9Sstevel@tonic-gate 			break;
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 		if (rv != PCICFG_SUCCESS)
6407c478bd9Sstevel@tonic-gate 			break;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 		if ((new_device = pcicfg_devi_find(attach_point,
64326947304SEvan Yan 		    trans_device, func & 7)) == NULL) {
6447c478bd9Sstevel@tonic-gate 			DEBUG0("Did'nt find device node just created\n");
6457c478bd9Sstevel@tonic-gate 			goto cleanup;
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 		/*
6497c478bd9Sstevel@tonic-gate 		 * Up until now, we have detected a non transparent bridge
6507c478bd9Sstevel@tonic-gate 		 * (ntbridge) as a part of the generic probe code and
6517c478bd9Sstevel@tonic-gate 		 * configured only one configuration
6527c478bd9Sstevel@tonic-gate 		 * header which is the side facing the host bus.
6537c478bd9Sstevel@tonic-gate 		 * Now, configure the other side and create children.
6547c478bd9Sstevel@tonic-gate 		 *
6557c478bd9Sstevel@tonic-gate 		 * In order to make the process simpler, lets load the device
6567c478bd9Sstevel@tonic-gate 		 * driver for the non transparent bridge as this is a
6577c478bd9Sstevel@tonic-gate 		 * Solaris bundled driver, and use its configuration map
6587c478bd9Sstevel@tonic-gate 		 * services rather than programming it here.
6597c478bd9Sstevel@tonic-gate 		 * If the driver is not bundled into Solaris, it must be
6607c478bd9Sstevel@tonic-gate 		 * first loaded and configured before performing any
6617c478bd9Sstevel@tonic-gate 		 * hotplug operations.
6627c478bd9Sstevel@tonic-gate 		 *
6637c478bd9Sstevel@tonic-gate 		 * This not only makes the code here simpler but also more
6647c478bd9Sstevel@tonic-gate 		 * generic.
6657c478bd9Sstevel@tonic-gate 		 *
6667c478bd9Sstevel@tonic-gate 		 * So here we go.
6677c478bd9Sstevel@tonic-gate 		 */
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 		/*
6707c478bd9Sstevel@tonic-gate 		 * check if this is a bridge in nontransparent mode
6717c478bd9Sstevel@tonic-gate 		 */
6727c478bd9Sstevel@tonic-gate 		if (pcicfg_is_ntbridge(new_device) != DDI_FAILURE) {
6737c478bd9Sstevel@tonic-gate 			DEBUG0("pcicfg: Found nontransparent bridge.\n");
6747c478bd9Sstevel@tonic-gate 
67526947304SEvan Yan 			rv = pcicfg_configure_ntbridge(new_device, bus,
67626947304SEvan Yan 			    trans_device);
6775af4ae46Sjveta 			if (rv != PCICFG_SUCCESS)
6787c478bd9Sstevel@tonic-gate 				goto cleanup;
6797c478bd9Sstevel@tonic-gate 		}
68026947304SEvan Yan 
6815c734816SRobert Mustacchi 		/*
6825c734816SRobert Mustacchi 		 * Note that we've successfully gone through and visited at
6835c734816SRobert Mustacchi 		 * least one node.
6845c734816SRobert Mustacchi 		 */
6855c734816SRobert Mustacchi 		visited++;
68626947304SEvan Yan next:
68726947304SEvan Yan 		/*
68826947304SEvan Yan 		 * Determine if ARI Forwarding should be enabled.
68926947304SEvan Yan 		 */
69026947304SEvan Yan 		if (func == 0) {
69126947304SEvan Yan 			if ((pcie_ari_supported(devi)
69226947304SEvan Yan 			    == PCIE_ARI_FORW_SUPPORTED) &&
69326947304SEvan Yan 			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
69426947304SEvan Yan 				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
69526947304SEvan Yan 					(void) ddi_prop_create(DDI_DEV_T_NONE,
69626947304SEvan Yan 					    devi,  DDI_PROP_CANSLEEP,
69726947304SEvan Yan 					    "ari-enabled", NULL, 0);
69826947304SEvan Yan 
69926947304SEvan Yan 					ari_mode = B_TRUE;
70026947304SEvan Yan 					max_function = PCICFG_MAX_ARI_FUNCTION;
70126947304SEvan Yan 				}
70226947304SEvan Yan 			}
70326947304SEvan Yan 		}
70426947304SEvan Yan 		if (ari_mode == B_TRUE) {
70526947304SEvan Yan 			int next_function;
70626947304SEvan Yan 
70726947304SEvan Yan 			DEBUG0("Next Function - ARI Device\n");
70826947304SEvan Yan 			if (pcie_ari_get_next_function(new_device,
70926947304SEvan Yan 			    &next_function) != DDI_SUCCESS)
71026947304SEvan Yan 				goto cleanup;
71126947304SEvan Yan 
71226947304SEvan Yan 			/*
7135c734816SRobert Mustacchi 			 * Check if there are more functions to probe.
71426947304SEvan Yan 			 */
71526947304SEvan Yan 			if (next_function == 0) {
71626947304SEvan Yan 				DEBUG0("Next Function - "
71726947304SEvan Yan 				    "No more ARI Functions\n");
71826947304SEvan Yan 				break;
71926947304SEvan Yan 			}
72026947304SEvan Yan 			func = next_function;
72126947304SEvan Yan 		} else {
72226947304SEvan Yan 			func++;
72326947304SEvan Yan 		}
72426947304SEvan Yan 		DEBUG1("Next Function - %x\n", func);
7257c478bd9Sstevel@tonic-gate 	}
7267c478bd9Sstevel@tonic-gate 
7275b2c4190SRobert Mustacchi 	/*
7285b2c4190SRobert Mustacchi 	 * At this point we have set up the various dev_info nodes that we
7295b2c4190SRobert Mustacchi 	 * expect to see in the tree and we must re-evaluate the general fabric
7305b2c4190SRobert Mustacchi 	 * settings such as the overall max payload size or the tagging that is
7315b2c4190SRobert Mustacchi 	 * enabled. However, as part the big theory statement in pcie.c, this
7325b2c4190SRobert Mustacchi 	 * can only be performed on a root port; however, that determination
7335b2c4190SRobert Mustacchi 	 * will be made by the fabric scanning logic.
7345b2c4190SRobert Mustacchi 	 */
7355b2c4190SRobert Mustacchi 	if (visited > 0 && is_pcie) {
7365b2c4190SRobert Mustacchi 		pcie_fabric_setup(devi);
7375b2c4190SRobert Mustacchi 	}
7385b2c4190SRobert Mustacchi 
7393fe80ca4SDan Cross 	ndi_devi_exit(devi);
7403fe80ca4SDan Cross 	ndi_devi_exit(ddi_get_parent(devi));
7417c478bd9Sstevel@tonic-gate 
7425c734816SRobert Mustacchi 	if (visited == 0)
7437c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);	/* probe failed */
7447c478bd9Sstevel@tonic-gate 	else
7457c478bd9Sstevel@tonic-gate 		return (PCICFG_SUCCESS);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate cleanup:
7487c478bd9Sstevel@tonic-gate 	/*
7497c478bd9Sstevel@tonic-gate 	 * Clean up a partially created "probe state" tree.
7507c478bd9Sstevel@tonic-gate 	 * There are no resources allocated to the in the
7517c478bd9Sstevel@tonic-gate 	 * probe state.
7527c478bd9Sstevel@tonic-gate 	 */
7537c478bd9Sstevel@tonic-gate 
75423c35297Sanish 	for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
75526947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
75626947304SEvan Yan 			continue;
75726947304SEvan Yan 
75826947304SEvan Yan 		if ((new_device = pcicfg_devi_find(devi, device, func))
75926947304SEvan Yan 		    == NULL) {
76070025d76Sjohnny 			continue;
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
76426947304SEvan Yan 		    device, func);
7657c478bd9Sstevel@tonic-gate 		/*
7667c478bd9Sstevel@tonic-gate 		 * If this was a bridge device it will have a
7677c478bd9Sstevel@tonic-gate 		 * probe handle - if not, no harm in calling this.
7687c478bd9Sstevel@tonic-gate 		 */
7697c478bd9Sstevel@tonic-gate 		(void) pcicfg_destroy_phdl(new_device);
770c0da6274SZhi-Jun Robin Fu 		if (is_pcie) {
771c0da6274SZhi-Jun Robin Fu 			/*
772c0da6274SZhi-Jun Robin Fu 			 * free pcie_bus_t for the sub-tree
773c0da6274SZhi-Jun Robin Fu 			 */
774c0da6274SZhi-Jun Robin Fu 			if (ddi_get_child(new_device) != NULL)
775c0da6274SZhi-Jun Robin Fu 				pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
776c0da6274SZhi-Jun Robin Fu 
777c0da6274SZhi-Jun Robin Fu 			pcie_fini_bus(new_device, PCIE_BUS_ALL);
778c0da6274SZhi-Jun Robin Fu 		}
7797c478bd9Sstevel@tonic-gate 		/*
7807c478bd9Sstevel@tonic-gate 		 * This will free up the node
7817c478bd9Sstevel@tonic-gate 		 */
7827c478bd9Sstevel@tonic-gate 		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
7837c478bd9Sstevel@tonic-gate 	}
7843fe80ca4SDan Cross 	ndi_devi_exit(devi);
7853fe80ca4SDan Cross 	ndi_devi_exit(ddi_get_parent(devi));
7867c478bd9Sstevel@tonic-gate 
7875af4ae46Sjveta 	/*
7885af4ae46Sjveta 	 * Use private return codes to help identify issues without debugging
7895af4ae46Sjveta 	 * enabled.  Resource limitations and mis-configurations are
7905af4ae46Sjveta 	 * probably the most likely caue of configuration failures on x86.
7915af4ae46Sjveta 	 * Convert return code back to values expected by the external
7925af4ae46Sjveta 	 * consumer before returning so we will warn only once on the first
7935af4ae46Sjveta 	 * encountered failure.
7945af4ae46Sjveta 	 */
7955af4ae46Sjveta 	if (rv == PCICFG_NORESRC) {
7965af4ae46Sjveta 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7975af4ae46Sjveta 
7985af4ae46Sjveta 		(void) ddi_pathname(devi, path);
7995af4ae46Sjveta 		cmn_err(CE_CONT, "?Not enough PCI resources to "
8005af4ae46Sjveta 		    "configure: %s\n", path);
8015af4ae46Sjveta 
8025af4ae46Sjveta 		kmem_free(path, MAXPATHLEN);
8035af4ae46Sjveta 		rv = PCICFG_FAILURE;
8045af4ae46Sjveta 	}
8055af4ae46Sjveta 
8065af4ae46Sjveta 	return (rv);
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate  * configure the child nodes of ntbridge. new_device points to ntbridge itself
8117c478bd9Sstevel@tonic-gate  */
8127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
81370025d76Sjohnny static int
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)8147c478bd9Sstevel@tonic-gate pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate 	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
8177c478bd9Sstevel@tonic-gate 	int			devno;
8187c478bd9Sstevel@tonic-gate 	dev_info_t		*new_ntbridgechild;
8197c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	config_handle;
8207c478bd9Sstevel@tonic-gate 	uint16_t		vid;
8217c478bd9Sstevel@tonic-gate 	uint64_t		next_bus;
8227c478bd9Sstevel@tonic-gate 	uint64_t		blen;
8237c478bd9Sstevel@tonic-gate 	ndi_ra_request_t	req;
82470025d76Sjohnny 	uint8_t			pcie_device_type = 0;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	/*
8277c478bd9Sstevel@tonic-gate 	 * If we need to do indirect config, lets create a property here
8287c478bd9Sstevel@tonic-gate 	 * to let the child conf map routine know that it has to
8297c478bd9Sstevel@tonic-gate 	 * go through the DDI calls, and not assume the devices are
8307c478bd9Sstevel@tonic-gate 	 * mapped directly under the host.
8317c478bd9Sstevel@tonic-gate 	 */
8327c478bd9Sstevel@tonic-gate 	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
83326947304SEvan Yan 	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) != DDI_SUCCESS) {
8347c478bd9Sstevel@tonic-gate 		DEBUG0("Cannot create indirect conf map property.\n");
8357c478bd9Sstevel@tonic-gate 		return ((int)PCICFG_FAILURE);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
83870025d76Sjohnny 	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
83970025d76Sjohnny 		return (PCICFG_FAILURE);
84070025d76Sjohnny 	/* check if we are PCIe device */
84170025d76Sjohnny 	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) {
84270025d76Sjohnny 		DEBUG0("PCIe device detected\n");
84370025d76Sjohnny 		pcie_device_type = 1;
84470025d76Sjohnny 	}
84570025d76Sjohnny 	pci_config_teardown(&config_handle);
8467c478bd9Sstevel@tonic-gate 	/* create Bus node properties for ntbridge. */
84770025d76Sjohnny 	if (pcicfg_set_busnode_props(new_device, pcie_device_type)
84826947304SEvan Yan 	    != PCICFG_SUCCESS) {
8497c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to set busnode props\n");
8507c478bd9Sstevel@tonic-gate 		return (rc);
8517c478bd9Sstevel@tonic-gate 	}
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/* For now: Lets only support one layer of child */
8547c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
8557c478bd9Sstevel@tonic-gate 	req.ra_len = 1;
85626947304SEvan Yan 	if (ndi_ra_alloc(ddi_get_parent(new_device), &req, &next_bus, &blen,
85726947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
8587c478bd9Sstevel@tonic-gate 		DEBUG0("ntbridge: Failed to get a bus number\n");
8595af4ae46Sjveta 		return (PCICFG_NORESRC);
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	/*
8657c478bd9Sstevel@tonic-gate 	 * Following will change, as we detect more bridges
8667c478bd9Sstevel@tonic-gate 	 * on the way.
8677c478bd9Sstevel@tonic-gate 	 */
8687c478bd9Sstevel@tonic-gate 	bus_range[0] = (int)next_bus;
8697c478bd9Sstevel@tonic-gate 	bus_range[1] = (int)next_bus;
8707c478bd9Sstevel@tonic-gate 
87126947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, "bus-range",
87226947304SEvan Yan 	    bus_range, 2) != DDI_SUCCESS) {
8737c478bd9Sstevel@tonic-gate 		DEBUG0("Cannot set ntbridge bus-range property");
8747c478bd9Sstevel@tonic-gate 		return (rc);
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	/*
8787c478bd9Sstevel@tonic-gate 	 * The other interface (away from the host) will be
8797c478bd9Sstevel@tonic-gate 	 * initialized by the nexus driver when it loads.
8807c478bd9Sstevel@tonic-gate 	 * We just have to set the registers and the nexus driver
8817c478bd9Sstevel@tonic-gate 	 * figures out the rest.
8827c478bd9Sstevel@tonic-gate 	 */
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	/*
8857c478bd9Sstevel@tonic-gate 	 * finally, lets load and attach the driver
8867c478bd9Sstevel@tonic-gate 	 * before configuring children of ntbridge.
8877c478bd9Sstevel@tonic-gate 	 */
8887c478bd9Sstevel@tonic-gate 	rc = ndi_devi_online(new_device, NDI_ONLINE_ATTACH|NDI_CONFIG);
8897c478bd9Sstevel@tonic-gate 	if (rc != NDI_SUCCESS) {
8907c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
8917c478bd9Sstevel@tonic-gate 		"pcicfg: Fail:cant load nontransparent bridgd driver..\n");
8927c478bd9Sstevel@tonic-gate 		rc = PCICFG_FAILURE;
8937c478bd9Sstevel@tonic-gate 		return (rc);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
8967c478bd9Sstevel@tonic-gate 
8975af4ae46Sjveta 	/* Now set aside pci resource allocation requests for our children */
89826947304SEvan Yan 	if (pcicfg_ntbridge_allocate_resources(new_device) != PCICFG_SUCCESS) {
8997c478bd9Sstevel@tonic-gate 		max_devs = 0;
9007c478bd9Sstevel@tonic-gate 		rc = PCICFG_FAILURE;
9017c478bd9Sstevel@tonic-gate 	} else
90223c35297Sanish 		max_devs = PCI_MAX_DEVICES;
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	/* Probe devices on 2nd bus */
9055af4ae46Sjveta 	rc = PCICFG_SUCCESS;
9067c478bd9Sstevel@tonic-gate 	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 		ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
909fa9e4066Sahrens 		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
91226947304SEvan Yan 		    != DDI_PROP_SUCCESS) {
9137c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
91426947304SEvan Yan 			    "Failed to add conf reg for ntbridge child.\n");
9157c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(new_ntbridgechild);
9167c478bd9Sstevel@tonic-gate 			rc = PCICFG_FAILURE;
9177c478bd9Sstevel@tonic-gate 			break;
9187c478bd9Sstevel@tonic-gate 		}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		if (pci_config_setup(new_ntbridgechild, &config_handle)
92126947304SEvan Yan 		    != DDI_SUCCESS) {
9227c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
92326947304SEvan Yan 			    "Cannot map ntbridge child %x\n", devno);
9247c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(new_ntbridgechild);
9257c478bd9Sstevel@tonic-gate 			rc = PCICFG_FAILURE;
9267c478bd9Sstevel@tonic-gate 			break;
9277c478bd9Sstevel@tonic-gate 		}
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 		/*
9307c478bd9Sstevel@tonic-gate 		 * See if there is any PCI HW at this location
9317c478bd9Sstevel@tonic-gate 		 * by reading the Vendor ID.  If it returns with 0xffff
9327c478bd9Sstevel@tonic-gate 		 * then there is no hardware at this location.
9337c478bd9Sstevel@tonic-gate 		 */
9347c478bd9Sstevel@tonic-gate 		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 		pci_config_teardown(&config_handle);
9377c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(new_ntbridgechild);
9387c478bd9Sstevel@tonic-gate 		if (vid	== 0xffff)
9397c478bd9Sstevel@tonic-gate 			continue;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 		/* Lets fake attachments points for each child, */
94226947304SEvan Yan 		rc = pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0);
9435af4ae46Sjveta 		if (rc != PCICFG_SUCCESS) {
9447c478bd9Sstevel@tonic-gate 			int old_dev = pcicfg_start_devno;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
94726947304SEvan Yan 			    "Error configuring ntbridge child dev=%d\n", devno);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 			while (old_dev != devno) {
9507c478bd9Sstevel@tonic-gate 				if (pcicfg_ntbridge_unconfigure_child(
95126947304SEvan Yan 				    new_device, old_dev) == PCICFG_FAILURE)
95226947304SEvan Yan 					cmn_err(CE_WARN, "Unconfig Error "
95326947304SEvan Yan 					    "ntbridge child dev=%d\n", old_dev);
9547c478bd9Sstevel@tonic-gate 				old_dev++;
9557c478bd9Sstevel@tonic-gate 			}
9567c478bd9Sstevel@tonic-gate 			break;
9577c478bd9Sstevel@tonic-gate 		}
9587c478bd9Sstevel@tonic-gate 	} /* devno loop */
9597c478bd9Sstevel@tonic-gate 	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
9607c478bd9Sstevel@tonic-gate 
9615af4ae46Sjveta 	if (rc == PCICFG_SUCCESS)
9627c478bd9Sstevel@tonic-gate 		rc = pcicfg_ntbridge_configure_done(new_device);
9637c478bd9Sstevel@tonic-gate 	else {
9647c478bd9Sstevel@tonic-gate 		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
9657c478bd9Sstevel@tonic-gate 		uint_t			*bus;
9667c478bd9Sstevel@tonic-gate 		int			k;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
96926947304SEvan Yan 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, &k)
97026947304SEvan Yan 		    != DDI_PROP_SUCCESS) {
9717c478bd9Sstevel@tonic-gate 			DEBUG0("Failed to read bus-range property\n");
9727c478bd9Sstevel@tonic-gate 			rc = PCICFG_FAILURE;
9737c478bd9Sstevel@tonic-gate 			return (rc);
9747c478bd9Sstevel@tonic-gate 		}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		DEBUG2("Need to free bus [%d] range [%d]\n",
97726947304SEvan Yan 		    bus[0], bus[1] - bus[0] + 1);
9787c478bd9Sstevel@tonic-gate 
97926947304SEvan Yan 		if (ndi_ra_free(ddi_get_parent(new_device), (uint64_t)bus[0],
98026947304SEvan Yan 		    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
98126947304SEvan Yan 		    NDI_RA_PASS) != NDI_SUCCESS) {
9827c478bd9Sstevel@tonic-gate 			DEBUG0("Failed to free a bus number\n");
9837c478bd9Sstevel@tonic-gate 			rc = PCICFG_FAILURE;
9841fb5b786Sprasad 			kmem_free(bus, k);
9857c478bd9Sstevel@tonic-gate 			return (rc);
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		/*
9897c478bd9Sstevel@tonic-gate 		 * Since no memory allocations are done for non transparent
9907c478bd9Sstevel@tonic-gate 		 * bridges (but instead we just set the handle with the
9917c478bd9Sstevel@tonic-gate 		 * already allocated memory, we just need to reset the
9927c478bd9Sstevel@tonic-gate 		 * following values before calling the destroy_phdl()
9937c478bd9Sstevel@tonic-gate 		 * function next, otherwise the it will try to free
9947c478bd9Sstevel@tonic-gate 		 * memory allocated as in case of a transparent bridge.
9957c478bd9Sstevel@tonic-gate 		 */
9967c478bd9Sstevel@tonic-gate 		entry->memory_len = 0;
997a6469d9bSprasad 		entry->pf_memory_len = 0;
9987c478bd9Sstevel@tonic-gate 		entry->io_len = 0;
9991fb5b786Sprasad 		kmem_free(bus, k);
10007c478bd9Sstevel@tonic-gate 		/* the following will free hole data. */
10017c478bd9Sstevel@tonic-gate 		(void) pcicfg_destroy_phdl(new_device);
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/*
10057c478bd9Sstevel@tonic-gate 	 * Unload driver just in case child configure failed!
10067c478bd9Sstevel@tonic-gate 	 */
10077c478bd9Sstevel@tonic-gate 	rc1 = ndi_devi_offline(new_device, 0);
10087c478bd9Sstevel@tonic-gate 	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
10097c478bd9Sstevel@tonic-gate 	if (rc1 != NDI_SUCCESS) {
10107c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
10117c478bd9Sstevel@tonic-gate 		"pcicfg: cant unload ntbridge driver..children.\n");
10127c478bd9Sstevel@tonic-gate 		rc = PCICFG_FAILURE;
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	return (rc);
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)10197c478bd9Sstevel@tonic-gate pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t		*phdl;
10227c478bd9Sstevel@tonic-gate 	ndi_ra_request_t	*mem_request;
1023a6469d9bSprasad 	ndi_ra_request_t	*pf_mem_request;
10247c478bd9Sstevel@tonic-gate 	ndi_ra_request_t	*io_request;
10257c478bd9Sstevel@tonic-gate 	uint64_t		boundbase, boundlen;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	phdl = pcicfg_find_phdl(dip);
10287c478bd9Sstevel@tonic-gate 	ASSERT(phdl);
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	mem_request = &phdl->mem_req;
1031a6469d9bSprasad 	pf_mem_request = &phdl->pf_mem_req;
10327c478bd9Sstevel@tonic-gate 	io_request  = &phdl->io_req;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	phdl->error = PCICFG_SUCCESS;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	/* Set Memory space handle for ntbridge */
10377c478bd9Sstevel@tonic-gate 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
103826947304SEvan Yan 	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
10397c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
104026947304SEvan Yan 		    "ntbridge: Mem resource information failure\n");
10417c478bd9Sstevel@tonic-gate 		phdl->memory_len  = 0;
10427c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate 	mem_request->ra_boundbase = boundbase;
10457c478bd9Sstevel@tonic-gate 	mem_request->ra_boundlen = boundbase + boundlen;
10467c478bd9Sstevel@tonic-gate 	mem_request->ra_len = boundlen;
10477c478bd9Sstevel@tonic-gate 	mem_request->ra_align_mask =
104826947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
10497c478bd9Sstevel@tonic-gate 	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	/*
10527c478bd9Sstevel@tonic-gate 	 * mem_request->ra_len =
10537c478bd9Sstevel@tonic-gate 	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
10547c478bd9Sstevel@tonic-gate 	 */
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	phdl->memory_base = phdl->memory_last = boundbase;
10577c478bd9Sstevel@tonic-gate 	phdl->memory_len  = boundlen;
10587c478bd9Sstevel@tonic-gate 	phdl->mem_hole.start = phdl->memory_base;
10597c478bd9Sstevel@tonic-gate 	phdl->mem_hole.len = mem_request->ra_len;
10607c478bd9Sstevel@tonic-gate 	phdl->mem_hole.next = (hole_t *)NULL;
10617c478bd9Sstevel@tonic-gate 
106226947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
106326947304SEvan Yan 	    boundlen, mem_request->ra_len);
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	/* Set IO space handle for ntbridge */
10667c478bd9Sstevel@tonic-gate 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
106726947304SEvan Yan 	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
10687c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
10697c478bd9Sstevel@tonic-gate 		phdl->io_len  = 0;
10707c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 	io_request->ra_len = boundlen;
10737c478bd9Sstevel@tonic-gate 	io_request->ra_align_mask =
107426947304SEvan Yan 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
10757c478bd9Sstevel@tonic-gate 	io_request->ra_boundbase = boundbase;
10767c478bd9Sstevel@tonic-gate 	io_request->ra_boundlen = boundbase + boundlen;
10777c478bd9Sstevel@tonic-gate 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	/*
10807c478bd9Sstevel@tonic-gate 	 * io_request->ra_len =
10817c478bd9Sstevel@tonic-gate 	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
10827c478bd9Sstevel@tonic-gate 	 */
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
10857c478bd9Sstevel@tonic-gate 	phdl->io_len  = (uint32_t)boundlen;
10867c478bd9Sstevel@tonic-gate 	phdl->io_hole.start = phdl->io_base;
10877c478bd9Sstevel@tonic-gate 	phdl->io_hole.len = io_request->ra_len;
10887c478bd9Sstevel@tonic-gate 	phdl->io_hole.next = (hole_t *)NULL;
10897c478bd9Sstevel@tonic-gate 
109026947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
109126947304SEvan Yan 	    boundlen, io_request->ra_len);
10927c478bd9Sstevel@tonic-gate 
1093a6469d9bSprasad 	/* Set Prefetchable Memory space handle for ntbridge */
1094a6469d9bSprasad 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
109526947304SEvan Yan 	    PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
1096a6469d9bSprasad 		cmn_err(CE_WARN,
109726947304SEvan Yan 		    "ntbridge: PF Mem resource information failure\n");
1098a6469d9bSprasad 		phdl->pf_memory_len  = 0;
1099a6469d9bSprasad 		return (PCICFG_FAILURE);
1100a6469d9bSprasad 	}
1101a6469d9bSprasad 	pf_mem_request->ra_boundbase = boundbase;
1102a6469d9bSprasad 	pf_mem_request->ra_boundlen = boundbase + boundlen;
1103a6469d9bSprasad 	pf_mem_request->ra_len = boundlen;
1104a6469d9bSprasad 	pf_mem_request->ra_align_mask =
110526947304SEvan Yan 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
1106a6469d9bSprasad 	pf_mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
1107a6469d9bSprasad 
1108a6469d9bSprasad 	/*
1109a6469d9bSprasad 	 * pf_mem_request->ra_len =
1110a6469d9bSprasad 	 * PCICFG_ROUND_UP(pf_mem_request->ra_len, PCICFG_MEMGRAN);
1111a6469d9bSprasad 	 */
1112a6469d9bSprasad 
1113a6469d9bSprasad 	phdl->pf_memory_base = phdl->pf_memory_last = boundbase;
1114a6469d9bSprasad 	phdl->pf_memory_len  = boundlen;
1115a6469d9bSprasad 	phdl->pf_mem_hole.start = phdl->pf_memory_base;
1116a6469d9bSprasad 	phdl->pf_mem_hole.len = pf_mem_request->ra_len;
1117a6469d9bSprasad 	phdl->pf_mem_hole.next = (hole_t *)NULL;
1118a6469d9bSprasad 
111926947304SEvan Yan 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of PF "
112026947304SEvan Yan 	    "memory\n", boundlen, pf_mem_request->ra_len);
1121a6469d9bSprasad 
1122a6469d9bSprasad 	DEBUG2("MEMORY BASE = [0x%lx] length [0x%lx]\n",
112326947304SEvan Yan 	    phdl->memory_base, phdl->memory_len);
11247c478bd9Sstevel@tonic-gate 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
112526947304SEvan Yan 	    phdl->io_base, phdl->io_len);
1126a6469d9bSprasad 	DEBUG2("PF MEMORY BASE = [0x%lx] length [0x%lx]\n",
112726947304SEvan Yan 	    phdl->pf_memory_base, phdl->pf_memory_len);
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)11337c478bd9Sstevel@tonic-gate pcicfg_ntbridge_configure_done(dev_info_t *dip)
11347c478bd9Sstevel@tonic-gate {
113500d0963fSdilpreet 	ppb_ranges_t range[PCICFG_RANGE_LEN];
11367c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t		*entry;
11377c478bd9Sstevel@tonic-gate 	uint_t			len;
113800d0963fSdilpreet 	pci_bus_range_t		bus_range;
11397c478bd9Sstevel@tonic-gate 	int			new_bus_range[2];
11407c478bd9Sstevel@tonic-gate 
1141a6469d9bSprasad 	DEBUG1("Configuring children for %p\n", dip);
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	entry = pcicfg_find_phdl(dip);
11447c478bd9Sstevel@tonic-gate 	ASSERT(entry);
11457c478bd9Sstevel@tonic-gate 
114626947304SEvan Yan 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
114700d0963fSdilpreet 	range[1].child_high = range[1].parent_high |=
114826947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
114900d0963fSdilpreet 	range[1].child_low = range[1].parent_low = (uint32_t)entry->memory_base;
11507c478bd9Sstevel@tonic-gate 
115100d0963fSdilpreet 	range[0].child_high = range[0].parent_high |=
115226947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_IO);
115300d0963fSdilpreet 	range[0].child_low = range[0].parent_low = (uint32_t)entry->io_base;
11547c478bd9Sstevel@tonic-gate 
115500d0963fSdilpreet 	range[2].child_high = range[2].parent_high |=
115626947304SEvan Yan 	    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
115700d0963fSdilpreet 	range[2].child_low = range[2].parent_low =
115826947304SEvan Yan 	    (uint32_t)entry->pf_memory_base;
1159a6469d9bSprasad 
116000d0963fSdilpreet 	len = sizeof (pci_bus_range_t);
1161a3282898Scth 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
116226947304SEvan Yan 	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
11637c478bd9Sstevel@tonic-gate 		DEBUG0("no bus-range property\n");
11647c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	new_bus_range[0] = bus_range.lo;	/* primary bus number */
11687c478bd9Sstevel@tonic-gate 	if (entry->highest_bus) {	/* secondary bus number */
11697c478bd9Sstevel@tonic-gate 		if (entry->highest_bus < bus_range.lo) {
11707c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
117126947304SEvan Yan 			    "ntbridge bus range invalid !(%d,%d)\n",
117226947304SEvan Yan 			    bus_range.lo, entry->highest_bus);
11737c478bd9Sstevel@tonic-gate 			new_bus_range[1] = bus_range.lo + entry->highest_bus;
11747c478bd9Sstevel@tonic-gate 		}
11757c478bd9Sstevel@tonic-gate 		else
11767c478bd9Sstevel@tonic-gate 			new_bus_range[1] = entry->highest_bus;
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 	else
11797c478bd9Sstevel@tonic-gate 		new_bus_range[1] = bus_range.hi;
11807c478bd9Sstevel@tonic-gate 
118126947304SEvan Yan 	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", new_bus_range[0],
118226947304SEvan Yan 	    new_bus_range[1]);
11837c478bd9Sstevel@tonic-gate 
118426947304SEvan Yan 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "bus-range",
118526947304SEvan Yan 	    new_bus_range, 2) != DDI_SUCCESS) {
11867c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to set bus-range property");
11877c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
11887c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
11897c478bd9Sstevel@tonic-gate 	}
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate #ifdef DEBUG
11927c478bd9Sstevel@tonic-gate 	{
11937c478bd9Sstevel@tonic-gate 		uint64_t	unused;
11947c478bd9Sstevel@tonic-gate 		unused = pcicfg_unused_space(&entry->io_hole, &len);
11957c478bd9Sstevel@tonic-gate 		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
119626947304SEvan Yan 		    unused, len);
11977c478bd9Sstevel@tonic-gate 	}
11987c478bd9Sstevel@tonic-gate #endif
11997c478bd9Sstevel@tonic-gate 
120000d0963fSdilpreet 	range[0].size_low = entry->io_len;
12017c478bd9Sstevel@tonic-gate 	if (pcicfg_update_ranges_prop(dip, &range[0])) {
12027c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to update ranges (i/o)\n");
12037c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
12047c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
12057c478bd9Sstevel@tonic-gate 	}
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate #ifdef DEBUG
12087c478bd9Sstevel@tonic-gate 	{
12097c478bd9Sstevel@tonic-gate 		uint64_t	unused;
12107c478bd9Sstevel@tonic-gate 		unused = pcicfg_unused_space(&entry->mem_hole, &len);
12117c478bd9Sstevel@tonic-gate 		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
121226947304SEvan Yan 		    unused, len);
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate #endif
12157c478bd9Sstevel@tonic-gate 
121600d0963fSdilpreet 	range[1].size_low = entry->memory_len;
12177c478bd9Sstevel@tonic-gate 	if (pcicfg_update_ranges_prop(dip, &range[1])) {
12187c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to update ranges (memory)\n");
12197c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
12207c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 
1223a6469d9bSprasad #ifdef DEBUG
1224a6469d9bSprasad 	{
1225a6469d9bSprasad 		uint64_t	unused;
1226a6469d9bSprasad 		unused = pcicfg_unused_space(&entry->pf_mem_hole, &len);
1227a6469d9bSprasad 		DEBUG2("ntbridge: Unused PF Mem space %llx bytes over"
122826947304SEvan Yan 		    " %d holes\n", unused, len);
1229a6469d9bSprasad 	}
1230a6469d9bSprasad #endif
1231a6469d9bSprasad 
123200d0963fSdilpreet 	range[2].size_low = entry->pf_memory_len;
1233a6469d9bSprasad 	if (pcicfg_update_ranges_prop(dip, &range[2])) {
1234a6469d9bSprasad 		DEBUG0("Failed to update ranges (PF memory)\n");
1235a6469d9bSprasad 		entry->error = PCICFG_FAILURE;
1236a6469d9bSprasad 		return (PCICFG_FAILURE);
1237a6469d9bSprasad 	}
1238a6469d9bSprasad 
12397c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_program_child(dev_info_t * dip)12437c478bd9Sstevel@tonic-gate pcicfg_ntbridge_program_child(dev_info_t *dip)
12447c478bd9Sstevel@tonic-gate {
124526947304SEvan Yan 	pcicfg_phdl_t	*entry;
124626947304SEvan Yan 	int		rc = PCICFG_SUCCESS;
12477c478bd9Sstevel@tonic-gate 	dev_info_t	*anode = dip;
12487c478bd9Sstevel@tonic-gate 
124926947304SEvan Yan 	/* Find the Hotplug Connection (CN) node */
125026947304SEvan Yan 	while ((anode != NULL) &&
125126947304SEvan Yan 	    (strcmp(ddi_binding_name(anode), "hp_attachment") != 0)) {
12527c478bd9Sstevel@tonic-gate 		anode = ddi_get_parent(anode);
12537c478bd9Sstevel@tonic-gate 	}
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	if (anode == NULL) {
12567c478bd9Sstevel@tonic-gate 		DEBUG0("ntbridge child tree not in PROBE state\n");
12577c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
12587c478bd9Sstevel@tonic-gate 	}
12597c478bd9Sstevel@tonic-gate 	entry = pcicfg_find_phdl(ddi_get_parent(anode));
12607c478bd9Sstevel@tonic-gate 	ASSERT(entry);
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	if (pcicfg_bridge_assign(dip, entry) == DDI_WALK_TERMINATE) {
12637c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
126426947304SEvan Yan 		    "ntbridge: Error assigning range for child %s\n",
126526947304SEvan Yan 		    ddi_get_name(dip));
12667c478bd9Sstevel@tonic-gate 		rc = PCICFG_FAILURE;
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 	return (rc);
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)12727c478bd9Sstevel@tonic-gate pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
12737c478bd9Sstevel@tonic-gate {
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	dev_info_t	*new_ntbridgechild;
1276ffb64830SJordan Paige Hendricks 	int		len, bus;
12777c478bd9Sstevel@tonic-gate 	uint16_t	vid;
12787c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	config_handle;
127900d0963fSdilpreet 	pci_bus_range_t pci_bus_range;
12807c478bd9Sstevel@tonic-gate 
128100d0963fSdilpreet 	len = sizeof (pci_bus_range_t);
1282a3282898Scth 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
128326947304SEvan Yan 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
12847c478bd9Sstevel@tonic-gate 		DEBUG0("no bus-range property\n");
12857c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
12867c478bd9Sstevel@tonic-gate 	}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
1291fa9e4066Sahrens 	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
129426947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
129526947304SEvan Yan 		cmn_err(CE_WARN, "Unconfigure: Failed to add conf reg prop for "
129626947304SEvan Yan 		    "ntbridge child.\n");
12977c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(new_ntbridgechild);
12987c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
12997c478bd9Sstevel@tonic-gate 	}
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	if (pci_config_setup(new_ntbridgechild, &config_handle)
130226947304SEvan Yan 	    != DDI_SUCCESS) {
130326947304SEvan Yan 		cmn_err(CE_WARN, "pcicfg: Cannot map ntbridge child %x\n",
130426947304SEvan Yan 		    devno);
13057c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(new_ntbridgechild);
13067c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
13077c478bd9Sstevel@tonic-gate 	}
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	/*
13107c478bd9Sstevel@tonic-gate 	 * See if there is any PCI HW at this location
13117c478bd9Sstevel@tonic-gate 	 * by reading the Vendor ID.  If it returns with 0xffff
13127c478bd9Sstevel@tonic-gate 	 * then there is no hardware at this location.
13137c478bd9Sstevel@tonic-gate 	 */
13147c478bd9Sstevel@tonic-gate 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	pci_config_teardown(&config_handle);
13177c478bd9Sstevel@tonic-gate 	(void) ndi_devi_free(new_ntbridgechild);
13187c478bd9Sstevel@tonic-gate 	if (vid	== 0xffff)
13197c478bd9Sstevel@tonic-gate 		return (PCICFG_NODEVICE);
13207c478bd9Sstevel@tonic-gate 
132126947304SEvan Yan 	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
13227c478bd9Sstevel@tonic-gate }
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate static uint_t
pcicfg_ntbridge_unconfigure(dev_info_t * dip)13257c478bd9Sstevel@tonic-gate pcicfg_ntbridge_unconfigure(dev_info_t *dip)
13267c478bd9Sstevel@tonic-gate {
13277c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
13287c478bd9Sstevel@tonic-gate 	uint_t			*bus;
13297c478bd9Sstevel@tonic-gate 	int			k, rc = DDI_FAILURE;
13307c478bd9Sstevel@tonic-gate 
133126947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range",
133226947304SEvan Yan 	    (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
13337c478bd9Sstevel@tonic-gate 		DEBUG0("ntbridge: Failed to read bus-range property\n");
13347c478bd9Sstevel@tonic-gate 		return (rc);
13357c478bd9Sstevel@tonic-gate 	}
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
133826947304SEvan Yan 	    bus[0], bus[1] - bus[0] + 1);
13397c478bd9Sstevel@tonic-gate 
134026947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
134126947304SEvan Yan 	    (uint64_t)(bus[1] - bus[0] + 1),
134226947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
13437c478bd9Sstevel@tonic-gate 		DEBUG0("ntbridge: Failed to free a bus number\n");
13447c478bd9Sstevel@tonic-gate 		kmem_free(bus, k);
13457c478bd9Sstevel@tonic-gate 		return (rc);
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	/*
13497c478bd9Sstevel@tonic-gate 	 * Since our resources will be freed at the parent level,
13507c478bd9Sstevel@tonic-gate 	 * just reset these values.
13517c478bd9Sstevel@tonic-gate 	 */
13527c478bd9Sstevel@tonic-gate 	entry->memory_len = 0;
13537c478bd9Sstevel@tonic-gate 	entry->io_len = 0;
1354a6469d9bSprasad 	entry->pf_memory_len = 0;
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	kmem_free(bus, k);
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	/* the following will also free hole data. */
13597c478bd9Sstevel@tonic-gate 	return (pcicfg_destroy_phdl(dip));
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate static int
pcicfg_is_ntbridge(dev_info_t * dip)13647c478bd9Sstevel@tonic-gate pcicfg_is_ntbridge(dev_info_t *dip)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	config_handle;
13677c478bd9Sstevel@tonic-gate 	uint8_t		class, subclass;
13687c478bd9Sstevel@tonic-gate 	int		rc = DDI_SUCCESS;
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
13717c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
137226947304SEvan Yan 		    "pcicfg: cannot map config space, to get map type\n");
13737c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate 	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
13767c478bd9Sstevel@tonic-gate 	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	/* check for class=6, subclass=9, for non transparent bridges.  */
13797c478bd9Sstevel@tonic-gate 	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
13807c478bd9Sstevel@tonic-gate 		rc = DDI_FAILURE;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
138326947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_VENID),
138426947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_DEVID),
138526947304SEvan Yan 	    rc);
13867c478bd9Sstevel@tonic-gate 	pci_config_teardown(&config_handle);
13877c478bd9Sstevel@tonic-gate 	return (rc);
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate static uint_t
pcicfg_ntbridge_child(dev_info_t * dip)13917c478bd9Sstevel@tonic-gate pcicfg_ntbridge_child(dev_info_t *dip)
13927c478bd9Sstevel@tonic-gate {
1393ffb64830SJordan Paige Hendricks 	int		len, val, rc = DDI_FAILURE;
13947c478bd9Sstevel@tonic-gate 	dev_info_t	*anode = dip;
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	/*
139726947304SEvan Yan 	 * Find the Hotplug Connection (CN) node
13987c478bd9Sstevel@tonic-gate 	 */
13997c478bd9Sstevel@tonic-gate 	while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
140026947304SEvan Yan 	    "hp_attachment") != 0)) {
14017c478bd9Sstevel@tonic-gate 		anode = ddi_get_parent(anode);
14027c478bd9Sstevel@tonic-gate 	}
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	if (anode == NULL) {
14057c478bd9Sstevel@tonic-gate 		DEBUG0("ntbridge child tree not in PROBE state\n");
14067c478bd9Sstevel@tonic-gate 		return (rc);
14077c478bd9Sstevel@tonic-gate 	}
14087c478bd9Sstevel@tonic-gate 	len = sizeof (int);
1409a3282898Scth 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(anode),
141026947304SEvan Yan 	    DDI_PROP_DONTPASS, PCI_DEV_CONF_MAP_PROP, (caddr_t)&val, &len)
141126947304SEvan Yan 	    != DDI_SUCCESS) {
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 		DEBUG1("ntbridge child: no \"%s\" property\n",
141426947304SEvan Yan 		    PCI_DEV_CONF_MAP_PROP);
14157c478bd9Sstevel@tonic-gate 		return (rc);
14167c478bd9Sstevel@tonic-gate 	}
14177c478bd9Sstevel@tonic-gate 	DEBUG0("ntbridge child: success\n");
14187c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)14227c478bd9Sstevel@tonic-gate pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
1423ffb64830SJordan Paige Hendricks     uint64_t *boundlen, uint_t space_type)
14247c478bd9Sstevel@tonic-gate {
14257c478bd9Sstevel@tonic-gate 	int		length, found = DDI_FAILURE, acount, i, ibridge;
14267c478bd9Sstevel@tonic-gate 	pci_regspec_t	*assigned;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
14297c478bd9Sstevel@tonic-gate 		return (found);
14307c478bd9Sstevel@tonic-gate 
143126947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
143226947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &length)
143326947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
14347c478bd9Sstevel@tonic-gate 		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
14357c478bd9Sstevel@tonic-gate 		return (found);
14367c478bd9Sstevel@tonic-gate 	}
14377c478bd9Sstevel@tonic-gate 	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
143826947304SEvan Yan 	    ddi_driver_name(dip));
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 	acount = length / sizeof (pci_regspec_t);
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	for (i = 0; i < acount; i++) {
144326947304SEvan Yan 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
144426947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
144526947304SEvan Yan 		    (space_type == PCI_BASE_SPACE_MEM)) {
144626947304SEvan Yan 			found = DDI_SUCCESS;
144726947304SEvan Yan 			break;
144826947304SEvan Yan 		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
144926947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].io_range_bar_offset) &&
145026947304SEvan Yan 		    (space_type == PCI_BASE_SPACE_IO)) {
145126947304SEvan Yan 			found = DDI_SUCCESS;
145226947304SEvan Yan 			break;
145326947304SEvan Yan 		} else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
145426947304SEvan Yan 		    pcicfg_indirect_map_devs[ibridge].
145526947304SEvan Yan 		    prefetch_mem_range_bar_offset) &&
145626947304SEvan Yan 		    (space_type == (PCI_BASE_SPACE_MEM |
145726947304SEvan Yan 		    PCI_BASE_PREF_M))) {
14587c478bd9Sstevel@tonic-gate 			found = DDI_SUCCESS;
14597c478bd9Sstevel@tonic-gate 			break;
14607c478bd9Sstevel@tonic-gate 		}
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
146326947304SEvan Yan 	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	if (found == DDI_SUCCESS)  {
14667c478bd9Sstevel@tonic-gate 		*boundbase = assigned[i].pci_phys_low;
14677c478bd9Sstevel@tonic-gate 		*boundlen = assigned[i].pci_size_low;
14687c478bd9Sstevel@tonic-gate 	}
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	kmem_free(assigned, length);
14717c478bd9Sstevel@tonic-gate 	return (found);
14727c478bd9Sstevel@tonic-gate }
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate /*
14757c478bd9Sstevel@tonic-gate  * This will turn  resources allocated by pcicfg_configure()
147626947304SEvan Yan  * and remove the device tree from the Hotplug Connection (CN)
14777c478bd9Sstevel@tonic-gate  * and below.  The routine assumes the devices have their
14787c478bd9Sstevel@tonic-gate  * drivers detached.
14797c478bd9Sstevel@tonic-gate  */
14807c478bd9Sstevel@tonic-gate int
pcicfg_unconfigure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)148126947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
148226947304SEvan Yan     pcicfg_flags_t flags)
14837c478bd9Sstevel@tonic-gate {
14847c478bd9Sstevel@tonic-gate 	dev_info_t *child_dip;
14857c478bd9Sstevel@tonic-gate 	int func;
14867c478bd9Sstevel@tonic-gate 	int i;
148726947304SEvan Yan 	int max_function, trans_device;
1488c0da6274SZhi-Jun Robin Fu 	boolean_t is_pcie;
148926947304SEvan Yan 
149026947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
149126947304SEvan Yan 		max_function = PCICFG_MAX_ARI_FUNCTION;
149226947304SEvan Yan 	else
149326947304SEvan Yan 		max_function = PCI_MAX_FUNCTIONS;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	/*
14967c478bd9Sstevel@tonic-gate 	 * Cycle through devices to make sure none are busy.
14977c478bd9Sstevel@tonic-gate 	 * If a single device is busy fail the whole unconfigure.
14987c478bd9Sstevel@tonic-gate 	 */
1499c0da6274SZhi-Jun Robin Fu 	is_pcie = is_pcie_fabric(devi);
1500c0da6274SZhi-Jun Robin Fu 
15013fe80ca4SDan Cross 	ndi_devi_enter(devi);
150226947304SEvan Yan 	for (func = 0; func < max_function; func++) {
150326947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
150426947304SEvan Yan 			continue;
150526947304SEvan Yan 
150626947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
150726947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
150826947304SEvan Yan 		else
150926947304SEvan Yan 			trans_device = device;
151026947304SEvan Yan 
151126947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device,
151226947304SEvan Yan 		    func & 7)) == NULL)
151370025d76Sjohnny 			continue;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
151626947304SEvan Yan 			continue;
151726947304SEvan Yan 
15187c478bd9Sstevel@tonic-gate 		/*
15197c478bd9Sstevel@tonic-gate 		 * Device function is busy. Before returning we have to
15207c478bd9Sstevel@tonic-gate 		 * put all functions back online which were taken
15217c478bd9Sstevel@tonic-gate 		 * offline during the process.
15227c478bd9Sstevel@tonic-gate 		 */
152326947304SEvan Yan 		DEBUG2("Device [0x%x] function [0x%x] is busy\n",
152426947304SEvan Yan 		    trans_device, func & 7);
152526947304SEvan Yan 		/*
152626947304SEvan Yan 		 * If we are only asked to offline one specific function,
152726947304SEvan Yan 		 * and that fails, we just simply return.
152826947304SEvan Yan 		 */
152926947304SEvan Yan 		if (function != PCICFG_ALL_FUNC)
15307c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
153126947304SEvan Yan 
153226947304SEvan Yan 		for (i = 0; i < func; i++) {
153326947304SEvan Yan 			if (max_function == PCICFG_MAX_ARI_FUNCTION)
153426947304SEvan Yan 				trans_device = i >> 3;
153526947304SEvan Yan 
153626947304SEvan Yan 			if ((child_dip = pcicfg_devi_find(devi, trans_device,
153726947304SEvan Yan 			    i & 7)) == NULL) {
153826947304SEvan Yan 				DEBUG0("No more devices to put back "
153926947304SEvan Yan 				    "on line!!\n");
154026947304SEvan Yan 				/*
154126947304SEvan Yan 				 * Made it through all functions
154226947304SEvan Yan 				 */
154326947304SEvan Yan 				continue;
154426947304SEvan Yan 			}
154526947304SEvan Yan 			if (ndi_devi_online(child_dip, NDI_CONFIG)
154626947304SEvan Yan 			    != NDI_SUCCESS) {
154726947304SEvan Yan 				DEBUG0("Failed to put back devices state\n");
1548c0da6274SZhi-Jun Robin Fu 				goto fail;
154926947304SEvan Yan 			}
15507c478bd9Sstevel@tonic-gate 		}
1551c0da6274SZhi-Jun Robin Fu 		goto fail;
15527c478bd9Sstevel@tonic-gate 	}
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	/*
155526947304SEvan Yan 	 * Now, tear down all devinfo nodes for this Connector.
15567c478bd9Sstevel@tonic-gate 	 */
155726947304SEvan Yan 	for (func = 0; func < max_function; func++) {
155826947304SEvan Yan 		if ((function != PCICFG_ALL_FUNC) && (function != func))
155926947304SEvan Yan 			continue;
156026947304SEvan Yan 
156126947304SEvan Yan 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
156226947304SEvan Yan 			trans_device = func >> 3; /* ARI Device */
156326947304SEvan Yan 		else
156426947304SEvan Yan 			trans_device = device;
156526947304SEvan Yan 
156626947304SEvan Yan 		if ((child_dip = pcicfg_devi_find(devi, trans_device, func & 7))
156726947304SEvan Yan 		    == NULL) {
156826947304SEvan Yan 			DEBUG2("No device at %x,%x\n", trans_device, func & 7);
156970025d76Sjohnny 			continue;
15707c478bd9Sstevel@tonic-gate 		}
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
157326947304SEvan Yan 		    trans_device, func & 7);
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
15767c478bd9Sstevel@tonic-gate 			if (pcicfg_ntbridge_unconfigure(child_dip) !=
157726947304SEvan Yan 			    PCICFG_SUCCESS) {
15787c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
157926947304SEvan Yan 				    "ntbridge: unconfigure failed\n");
1580c0da6274SZhi-Jun Robin Fu 				goto fail;
15817c478bd9Sstevel@tonic-gate 			}
15827c478bd9Sstevel@tonic-gate 
1583c0da6274SZhi-Jun Robin Fu 		if (pcicfg_teardown_device(child_dip, flags, is_pcie)
158426947304SEvan Yan 		    != PCICFG_SUCCESS) {
15857c478bd9Sstevel@tonic-gate 			DEBUG2("Failed to tear down device [0x%x]"
158626947304SEvan Yan 			    "function [0x%x]\n", trans_device, func & 7);
1587c0da6274SZhi-Jun Robin Fu 			goto fail;
15887c478bd9Sstevel@tonic-gate 		}
15897c478bd9Sstevel@tonic-gate 	}
159026947304SEvan Yan 
159126947304SEvan Yan 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
159226947304SEvan Yan 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
159326947304SEvan Yan 		(void) pcie_ari_disable(devi);
159426947304SEvan Yan 	}
159526947304SEvan Yan 
15963fe80ca4SDan Cross 	ndi_devi_exit(devi);
15977c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
1598c0da6274SZhi-Jun Robin Fu 
1599c0da6274SZhi-Jun Robin Fu fail:
16003fe80ca4SDan Cross 	ndi_devi_exit(devi);
1601c0da6274SZhi-Jun Robin Fu 	return (PCICFG_FAILURE);
16027c478bd9Sstevel@tonic-gate }
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate static int
pcicfg_teardown_device(dev_info_t * dip,pcicfg_flags_t flags,boolean_t is_pcie)1605c0da6274SZhi-Jun Robin Fu pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
16067c478bd9Sstevel@tonic-gate {
1607a6469d9bSprasad 	ddi_acc_handle_t	handle;
1608ffb64830SJordan Paige Hendricks 	int			ret;
1609a6469d9bSprasad 
16107c478bd9Sstevel@tonic-gate 	/*
16117c478bd9Sstevel@tonic-gate 	 * Free up resources associated with 'dip'
16127c478bd9Sstevel@tonic-gate 	 */
161326947304SEvan Yan 	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
16147c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to free resources\n");
16157c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
16167c478bd9Sstevel@tonic-gate 	}
16177c478bd9Sstevel@tonic-gate 
1618a6469d9bSprasad 	/*
1619a6469d9bSprasad 	 * disable the device
1620a6469d9bSprasad 	 */
1621ffb64830SJordan Paige Hendricks 
1622ffb64830SJordan Paige Hendricks 	ret = pcicfg_config_setup(dip, &handle);
1623ffb64830SJordan Paige Hendricks 	if (ret == PCICFG_SUCCESS) {
1624ffb64830SJordan Paige Hendricks 		pcicfg_device_off(handle);
1625ffb64830SJordan Paige Hendricks 		pcicfg_config_teardown(&handle);
1626ffb64830SJordan Paige Hendricks 	} else if (ret != PCICFG_NODEVICE) {
1627ffb64830SJordan Paige Hendricks 		/*
1628ffb64830SJordan Paige Hendricks 		 * It is possible the device no longer exists -- for instance,
1629ffb64830SJordan Paige Hendricks 		 * if the device has been pulled from a hotpluggable slot on the
1630ffb64830SJordan Paige Hendricks 		 * system. In this case, do not fail the teardown, though there
1631ffb64830SJordan Paige Hendricks 		 * is less to clean up.
1632ffb64830SJordan Paige Hendricks 		 */
1633a6469d9bSprasad 		return (PCICFG_FAILURE);
1634ffb64830SJordan Paige Hendricks 	}
1635a6469d9bSprasad 
1636c0da6274SZhi-Jun Robin Fu 	if (is_pcie) {
1637c0da6274SZhi-Jun Robin Fu 		/*
1638c0da6274SZhi-Jun Robin Fu 		 * free pcie_bus_t for the sub-tree
1639c0da6274SZhi-Jun Robin Fu 		 */
1640c0da6274SZhi-Jun Robin Fu 		if (ddi_get_child(dip) != NULL)
1641c0da6274SZhi-Jun Robin Fu 			pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
1642c0da6274SZhi-Jun Robin Fu 
1643c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(dip, PCIE_BUS_ALL);
1644c0da6274SZhi-Jun Robin Fu 	}
1645c0da6274SZhi-Jun Robin Fu 
16467c478bd9Sstevel@tonic-gate 	/*
16477c478bd9Sstevel@tonic-gate 	 * The framework provides this routine which can
16487c478bd9Sstevel@tonic-gate 	 * tear down a sub-tree.
16497c478bd9Sstevel@tonic-gate 	 */
16507c478bd9Sstevel@tonic-gate 	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
16517c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to offline and remove node\n");
16527c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
16537c478bd9Sstevel@tonic-gate 	}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
16567c478bd9Sstevel@tonic-gate }
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate /*
16597c478bd9Sstevel@tonic-gate  * BEGIN GENERIC SUPPORT ROUTINES
16607c478bd9Sstevel@tonic-gate  */
16617c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)16627c478bd9Sstevel@tonic-gate pcicfg_find_phdl(dev_info_t *dip)
16637c478bd9Sstevel@tonic-gate {
16647c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t *entry;
16657c478bd9Sstevel@tonic-gate 	mutex_enter(&pcicfg_list_mutex);
16667c478bd9Sstevel@tonic-gate 	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
16677c478bd9Sstevel@tonic-gate 		if (entry->dip == dip) {
16687c478bd9Sstevel@tonic-gate 			mutex_exit(&pcicfg_list_mutex);
16697c478bd9Sstevel@tonic-gate 			return (entry);
16707c478bd9Sstevel@tonic-gate 		}
16717c478bd9Sstevel@tonic-gate 	}
16727c478bd9Sstevel@tonic-gate 	mutex_exit(&pcicfg_list_mutex);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	/*
16757c478bd9Sstevel@tonic-gate 	 * Did'nt find entry - create one
16767c478bd9Sstevel@tonic-gate 	 */
16777c478bd9Sstevel@tonic-gate 	return (pcicfg_create_phdl(dip));
16787c478bd9Sstevel@tonic-gate }
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)16817c478bd9Sstevel@tonic-gate pcicfg_create_phdl(dev_info_t *dip)
16827c478bd9Sstevel@tonic-gate {
16837c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t *new;
16847c478bd9Sstevel@tonic-gate 
168526947304SEvan Yan 	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), KM_SLEEP);
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	new->dip = dip;
16887c478bd9Sstevel@tonic-gate 	mutex_enter(&pcicfg_list_mutex);
16897c478bd9Sstevel@tonic-gate 	new->next = pcicfg_phdl_list;
16907c478bd9Sstevel@tonic-gate 	pcicfg_phdl_list = new;
16917c478bd9Sstevel@tonic-gate 	mutex_exit(&pcicfg_list_mutex);
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	return (new);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate static int
pcicfg_destroy_phdl(dev_info_t * dip)16977c478bd9Sstevel@tonic-gate pcicfg_destroy_phdl(dev_info_t *dip)
16987c478bd9Sstevel@tonic-gate {
16997c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t *entry;
17007c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t *follow = NULL;
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	mutex_enter(&pcicfg_list_mutex);
17037c478bd9Sstevel@tonic-gate 	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
170426947304SEvan Yan 	    entry = entry->next) {
17057c478bd9Sstevel@tonic-gate 		if (entry->dip == dip) {
17067c478bd9Sstevel@tonic-gate 			if (entry == pcicfg_phdl_list) {
17077c478bd9Sstevel@tonic-gate 				pcicfg_phdl_list = entry->next;
17087c478bd9Sstevel@tonic-gate 			} else {
17097c478bd9Sstevel@tonic-gate 				follow->next = entry->next;
17107c478bd9Sstevel@tonic-gate 			}
17117c478bd9Sstevel@tonic-gate 			/*
17127c478bd9Sstevel@tonic-gate 			 * If this entry has any allocated memory
17137c478bd9Sstevel@tonic-gate 			 * or IO space associated with it, that
17147c478bd9Sstevel@tonic-gate 			 * must be freed up.
17157c478bd9Sstevel@tonic-gate 			 */
17167c478bd9Sstevel@tonic-gate 			if (entry->memory_len > 0) {
17177c478bd9Sstevel@tonic-gate 				(void) ndi_ra_free(ddi_get_parent(dip),
171826947304SEvan Yan 				    entry->memory_base, entry->memory_len,
171926947304SEvan Yan 				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
17207c478bd9Sstevel@tonic-gate 			}
17217c478bd9Sstevel@tonic-gate 			pcicfg_free_hole(&entry->mem_hole);
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 			if (entry->io_len > 0) {
17247c478bd9Sstevel@tonic-gate 				(void) ndi_ra_free(ddi_get_parent(dip),
172526947304SEvan Yan 				    entry->io_base, entry->io_len,
172626947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS);
17277c478bd9Sstevel@tonic-gate 			}
17287c478bd9Sstevel@tonic-gate 			pcicfg_free_hole(&entry->io_hole);
17297c478bd9Sstevel@tonic-gate 
1730a6469d9bSprasad 			if (entry->pf_memory_len > 0) {
1731a6469d9bSprasad 				(void) ndi_ra_free(ddi_get_parent(dip),
173226947304SEvan Yan 				    entry->pf_memory_base, entry->pf_memory_len,
173326947304SEvan Yan 				    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
1734a6469d9bSprasad 			}
1735a6469d9bSprasad 			pcicfg_free_hole(&entry->pf_mem_hole);
1736a6469d9bSprasad 
17377c478bd9Sstevel@tonic-gate 			/*
17387c478bd9Sstevel@tonic-gate 			 * Destroy this entry
17397c478bd9Sstevel@tonic-gate 			 */
17407c478bd9Sstevel@tonic-gate 			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
17417c478bd9Sstevel@tonic-gate 			mutex_exit(&pcicfg_list_mutex);
17427c478bd9Sstevel@tonic-gate 			return (PCICFG_SUCCESS);
17437c478bd9Sstevel@tonic-gate 		}
17447c478bd9Sstevel@tonic-gate 	}
17457c478bd9Sstevel@tonic-gate 	mutex_exit(&pcicfg_list_mutex);
17467c478bd9Sstevel@tonic-gate 	/*
17477c478bd9Sstevel@tonic-gate 	 * Did'nt find the entry
17487c478bd9Sstevel@tonic-gate 	 */
17497c478bd9Sstevel@tonic-gate 	return (PCICFG_FAILURE);
17507c478bd9Sstevel@tonic-gate }
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)17537c478bd9Sstevel@tonic-gate pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t handle;
17567c478bd9Sstevel@tonic-gate 	pci_regspec_t *reg;
17577c478bd9Sstevel@tonic-gate 	int length;
17587c478bd9Sstevel@tonic-gate 	int rcount;
17597c478bd9Sstevel@tonic-gate 	int i;
17607c478bd9Sstevel@tonic-gate 	int offset;
17617c478bd9Sstevel@tonic-gate 	uint64_t mem_answer;
17627c478bd9Sstevel@tonic-gate 	uint32_t io_answer;
17637c478bd9Sstevel@tonic-gate 	uint8_t header_type;
176400d0963fSdilpreet 	ppb_ranges_t range[PCICFG_RANGE_LEN];
17657c478bd9Sstevel@tonic-gate 	int bus_range[2];
17667c478bd9Sstevel@tonic-gate 	uint64_t mem_residual;
1767a6469d9bSprasad 	uint64_t pf_mem_residual;
17687c478bd9Sstevel@tonic-gate 	uint64_t io_residual;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
17717c478bd9Sstevel@tonic-gate 
177226947304SEvan Yan 	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 	entry->error = PCICFG_SUCCESS;
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	if (entry == NULL) {
17777c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to get entry\n");
17787c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
17797c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
17807c478bd9Sstevel@tonic-gate 	}
17817c478bd9Sstevel@tonic-gate 
178226947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
17837c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to map config space!\n");
17847c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
17857c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
17867c478bd9Sstevel@tonic-gate 	}
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
17917c478bd9Sstevel@tonic-gate 
179226947304SEvan Yan 		bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 		(void) pcicfg_setup_bridge(entry, handle);
17957c478bd9Sstevel@tonic-gate 
179600d0963fSdilpreet 		range[0].child_high = range[0].parent_high |=
179726947304SEvan Yan 		    (PCI_REG_REL_M | PCI_ADDR_IO);
179826947304SEvan Yan 		range[0].child_low = range[0].parent_low = entry->io_last;
179900d0963fSdilpreet 		range[1].child_high = range[1].parent_high |=
180026947304SEvan Yan 		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
180100d0963fSdilpreet 		range[1].child_low = range[1].parent_low =
180226947304SEvan Yan 		    entry->memory_last;
180300d0963fSdilpreet 		range[2].child_high = range[2].parent_high |=
180426947304SEvan Yan 		    (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
180500d0963fSdilpreet 		range[2].child_low = range[2].parent_low =
180626947304SEvan Yan 		    entry->pf_memory_last;
18077c478bd9Sstevel@tonic-gate 
18083fe80ca4SDan Cross 		ndi_devi_enter(dip);
18097c478bd9Sstevel@tonic-gate 		ddi_walk_devs(ddi_get_child(dip),
181026947304SEvan Yan 		    pcicfg_bridge_assign, (void *)entry);
18113fe80ca4SDan Cross 		ndi_devi_exit(dip);
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 		(void) pcicfg_update_bridge(entry, handle);
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
18167c478bd9Sstevel@tonic-gate 		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
181926947304SEvan Yan 		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
18207c478bd9Sstevel@tonic-gate 			DEBUG0("Failed to set bus-range property");
18217c478bd9Sstevel@tonic-gate 			entry->error = PCICFG_FAILURE;
18221fb5b786Sprasad 			(void) pcicfg_config_teardown(&handle);
18237c478bd9Sstevel@tonic-gate 			return (DDI_WALK_TERMINATE);
18247c478bd9Sstevel@tonic-gate 		}
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 		/*
18277c478bd9Sstevel@tonic-gate 		 * Put back memory and I/O space not allocated
18287c478bd9Sstevel@tonic-gate 		 * under the bridge.
18297c478bd9Sstevel@tonic-gate 		 */
18307c478bd9Sstevel@tonic-gate 		mem_residual = entry->memory_len -
183126947304SEvan Yan 		    (entry->memory_last - entry->memory_base);
18327c478bd9Sstevel@tonic-gate 		if (mem_residual > 0) {
18337c478bd9Sstevel@tonic-gate 			(void) ndi_ra_free(ddi_get_parent(dip),
183426947304SEvan Yan 			    entry->memory_last, mem_residual,
183526947304SEvan Yan 			    NDI_RA_TYPE_MEM, NDI_RA_PASS);
18367c478bd9Sstevel@tonic-gate 		}
18377c478bd9Sstevel@tonic-gate 
183826947304SEvan Yan 		io_residual = entry->io_len - (entry->io_last - entry->io_base);
18397c478bd9Sstevel@tonic-gate 		if (io_residual > 0) {
184026947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(dip), entry->io_last,
184126947304SEvan Yan 			    io_residual, NDI_RA_TYPE_IO, NDI_RA_PASS);
18427c478bd9Sstevel@tonic-gate 		}
18437c478bd9Sstevel@tonic-gate 
1844a6469d9bSprasad 		pf_mem_residual = entry->pf_memory_len -
184526947304SEvan Yan 		    (entry->pf_memory_last - entry->pf_memory_base);
1846a6469d9bSprasad 		if (pf_mem_residual > 0) {
1847a6469d9bSprasad 			(void) ndi_ra_free(ddi_get_parent(dip),
184826947304SEvan Yan 			    entry->pf_memory_last, pf_mem_residual,
184926947304SEvan Yan 			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
1850a6469d9bSprasad 		}
1851a6469d9bSprasad 
18527c478bd9Sstevel@tonic-gate 		if (entry->io_len > 0) {
185300d0963fSdilpreet 			range[0].size_low = entry->io_last - entry->io_base;
18547c478bd9Sstevel@tonic-gate 			if (pcicfg_update_ranges_prop(dip, &range[0])) {
18557c478bd9Sstevel@tonic-gate 				DEBUG0("Failed to update ranges (i/o)\n");
18567c478bd9Sstevel@tonic-gate 				entry->error = PCICFG_FAILURE;
18571fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
18587c478bd9Sstevel@tonic-gate 				return (DDI_WALK_TERMINATE);
18597c478bd9Sstevel@tonic-gate 			}
18607c478bd9Sstevel@tonic-gate 		}
18617c478bd9Sstevel@tonic-gate 		if (entry->memory_len > 0) {
186200d0963fSdilpreet 			range[1].size_low =
186326947304SEvan Yan 			    entry->memory_last - entry->memory_base;
18647c478bd9Sstevel@tonic-gate 			if (pcicfg_update_ranges_prop(dip, &range[1])) {
18657c478bd9Sstevel@tonic-gate 				DEBUG0("Failed to update ranges (memory)\n");
18667c478bd9Sstevel@tonic-gate 				entry->error = PCICFG_FAILURE;
18671fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
18687c478bd9Sstevel@tonic-gate 				return (DDI_WALK_TERMINATE);
18697c478bd9Sstevel@tonic-gate 			}
18707c478bd9Sstevel@tonic-gate 		}
1871a6469d9bSprasad 		if (entry->pf_memory_len > 0) {
187200d0963fSdilpreet 			range[2].size_low =
187326947304SEvan Yan 			    entry->pf_memory_last - entry->pf_memory_base;
1874a6469d9bSprasad 			if (pcicfg_update_ranges_prop(dip, &range[2])) {
1875a6469d9bSprasad 				DEBUG0("Failed to update ranges (PF memory)\n");
1876a6469d9bSprasad 				entry->error = PCICFG_FAILURE;
18771fb5b786Sprasad 				(void) pcicfg_config_teardown(&handle);
1878a6469d9bSprasad 				return (DDI_WALK_TERMINATE);
1879a6469d9bSprasad 			}
1880a6469d9bSprasad 		}
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 		(void) pcicfg_device_on(handle);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 		PCICFG_DUMP_BRIDGE_CONFIG(handle);
18857c478bd9Sstevel@tonic-gate 
18861fb5b786Sprasad 		(void) pcicfg_config_teardown(&handle);
18871fb5b786Sprasad 
18887c478bd9Sstevel@tonic-gate 		return (DDI_WALK_PRUNECHILD);
18897c478bd9Sstevel@tonic-gate 	}
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	/*
18927c478bd9Sstevel@tonic-gate 	 * If there is an interrupt pin set program
18937c478bd9Sstevel@tonic-gate 	 * interrupt line with default values.
18947c478bd9Sstevel@tonic-gate 	 */
18957c478bd9Sstevel@tonic-gate 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
18967c478bd9Sstevel@tonic-gate 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
18977c478bd9Sstevel@tonic-gate 	}
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	/*
19007c478bd9Sstevel@tonic-gate 	 * A single device (under a bridge).
19017c478bd9Sstevel@tonic-gate 	 * For each "reg" property with a length, allocate memory
19027c478bd9Sstevel@tonic-gate 	 * and program the base registers.
19037c478bd9Sstevel@tonic-gate 	 */
190426947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
190526947304SEvan Yan 	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
19067c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to read reg property\n");
19077c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
19081fb5b786Sprasad 		(void) pcicfg_config_teardown(&handle);
19097c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	rcount = length / sizeof (pci_regspec_t);
19137c478bd9Sstevel@tonic-gate 	offset = PCI_CONF_BASE0;
19147c478bd9Sstevel@tonic-gate 	for (i = 0; i < rcount; i++) {
191526947304SEvan Yan 		if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
19167c478bd9Sstevel@tonic-gate 
19177c478bd9Sstevel@tonic-gate 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
19207c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
19217c478bd9Sstevel@tonic-gate 
1922a6469d9bSprasad 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
1923a6469d9bSprasad 					/* allocate prefetchable memory */
1924a6469d9bSprasad 					pcicfg_get_pf_mem(entry,
1925a6469d9bSprasad 					    reg[i].pci_size_low, &mem_answer);
1926a6469d9bSprasad 				} else { /* get non prefetchable memory */
1927a6469d9bSprasad 					pcicfg_get_mem(entry,
192826947304SEvan Yan 					    reg[i].pci_size_low, &mem_answer);
1929a6469d9bSprasad 				}
19307c478bd9Sstevel@tonic-gate 				pci_config_put64(handle, offset, mem_answer);
19317c478bd9Sstevel@tonic-gate 				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
193226947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
19337c478bd9Sstevel@tonic-gate 				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
193426947304SEvan Yan 				    offset + 4,
193526947304SEvan Yan 				    pci_config_get32(handle, offset + 4));
19367c478bd9Sstevel@tonic-gate 
1937a6469d9bSprasad 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
1938a6469d9bSprasad 				reg[i].pci_phys_low = PCICFG_LOADDR(mem_answer);
193926947304SEvan Yan 				reg[i].pci_phys_mid = PCICFG_HIADDR(mem_answer);
19407c478bd9Sstevel@tonic-gate 				break;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
1943a6469d9bSprasad 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
1944a6469d9bSprasad 					/* allocate prefetchable memory */
1945a6469d9bSprasad 					pcicfg_get_pf_mem(entry,
1946a6469d9bSprasad 					    reg[i].pci_size_low, &mem_answer);
1947a6469d9bSprasad 				} else {
1948a6469d9bSprasad 					/* get non prefetchable memory */
1949a6469d9bSprasad 					pcicfg_get_mem(entry,
195026947304SEvan Yan 					    reg[i].pci_size_low, &mem_answer);
1951a6469d9bSprasad 				}
1952a6469d9bSprasad 
195326947304SEvan Yan 				pci_config_put32(handle, offset,
195426947304SEvan Yan 				    (uint32_t)mem_answer);
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
195726947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
19587c478bd9Sstevel@tonic-gate 
1959a6469d9bSprasad 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
19607c478bd9Sstevel@tonic-gate 				reg[i].pci_phys_low = (uint32_t)mem_answer;
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 				break;
19637c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
19647c478bd9Sstevel@tonic-gate 				/* allocate I/O space from the allocator */
19657c478bd9Sstevel@tonic-gate 
196626947304SEvan Yan 				(void) pcicfg_get_io(entry, reg[i].pci_size_low,
196726947304SEvan Yan 				    &io_answer);
19687c478bd9Sstevel@tonic-gate 				pci_config_put32(handle, offset, io_answer);
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
197126947304SEvan Yan 				    offset, pci_config_get32(handle, offset));
19727c478bd9Sstevel@tonic-gate 
1973a6469d9bSprasad 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
19747c478bd9Sstevel@tonic-gate 				reg[i].pci_phys_low = io_answer;
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 				break;
19777c478bd9Sstevel@tonic-gate 			default:
19787c478bd9Sstevel@tonic-gate 				DEBUG0("Unknown register type\n");
19797c478bd9Sstevel@tonic-gate 				kmem_free(reg, length);
19807c478bd9Sstevel@tonic-gate 				(void) pcicfg_config_teardown(&handle);
19817c478bd9Sstevel@tonic-gate 				entry->error = PCICFG_FAILURE;
19827c478bd9Sstevel@tonic-gate 				return (DDI_WALK_TERMINATE);
19837c478bd9Sstevel@tonic-gate 			} /* switch */
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 			/*
19867c478bd9Sstevel@tonic-gate 			 * Now that memory locations are assigned,
19877c478bd9Sstevel@tonic-gate 			 * update the assigned address property.
19887c478bd9Sstevel@tonic-gate 			 */
198926947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip, &reg[i])
199026947304SEvan Yan 			    != PCICFG_SUCCESS) {
19917c478bd9Sstevel@tonic-gate 				kmem_free(reg, length);
19927c478bd9Sstevel@tonic-gate 				(void) pcicfg_config_teardown(&handle);
19937c478bd9Sstevel@tonic-gate 				entry->error = PCICFG_FAILURE;
19947c478bd9Sstevel@tonic-gate 				return (DDI_WALK_TERMINATE);
19957c478bd9Sstevel@tonic-gate 			}
19967c478bd9Sstevel@tonic-gate 		}
19977c478bd9Sstevel@tonic-gate 	}
19987c478bd9Sstevel@tonic-gate 	(void) pcicfg_device_on(handle);
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	PCICFG_DUMP_DEVICE_CONFIG(handle);
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 	(void) pcicfg_config_teardown(&handle);
20037c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)reg, length);
20047c478bd9Sstevel@tonic-gate 	return (DDI_WALK_CONTINUE);
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate static int
pcicfg_device_assign(dev_info_t * dip)20087c478bd9Sstevel@tonic-gate pcicfg_device_assign(dev_info_t *dip)
20097c478bd9Sstevel@tonic-gate {
20107c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	handle;
20117c478bd9Sstevel@tonic-gate 	pci_regspec_t		*reg;
20127c478bd9Sstevel@tonic-gate 	int			length;
20137c478bd9Sstevel@tonic-gate 	int			rcount;
20147c478bd9Sstevel@tonic-gate 	int			i;
20157c478bd9Sstevel@tonic-gate 	int			offset;
20167c478bd9Sstevel@tonic-gate 	ndi_ra_request_t	request;
20177c478bd9Sstevel@tonic-gate 	uint64_t		answer;
20187c478bd9Sstevel@tonic-gate 	uint64_t		alen;
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	DEBUG1("%llx now under configuration\n", dip);
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 	/* request.ra_len = PCICFG_ROUND_UP(request.ra_len, PCICFG_IOGRAN); */
20237c478bd9Sstevel@tonic-gate 	if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 		return (pcicfg_ntbridge_program_child(dip));
20267c478bd9Sstevel@tonic-gate 	}
20277c478bd9Sstevel@tonic-gate 	/*
20287c478bd9Sstevel@tonic-gate 	 * XXX Failure here should be noted
20297c478bd9Sstevel@tonic-gate 	 */
203026947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
203126947304SEvan Yan 	    (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
20327c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to read reg property\n");
20337c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
20347c478bd9Sstevel@tonic-gate 	}
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
20377c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to map config space!\n");
20381fb5b786Sprasad 		kmem_free(reg, length);
20397c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
20407c478bd9Sstevel@tonic-gate 	}
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 	/*
20437c478bd9Sstevel@tonic-gate 	 * A single device
20447c478bd9Sstevel@tonic-gate 	 *
20457c478bd9Sstevel@tonic-gate 	 * For each "reg" property with a length, allocate memory
20467c478bd9Sstevel@tonic-gate 	 * and program the base registers.
20477c478bd9Sstevel@tonic-gate 	 */
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	/*
20507c478bd9Sstevel@tonic-gate 	 * If there is an interrupt pin set program
20517c478bd9Sstevel@tonic-gate 	 * interrupt line with default values.
20527c478bd9Sstevel@tonic-gate 	 */
20537c478bd9Sstevel@tonic-gate 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
20547c478bd9Sstevel@tonic-gate 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
20557c478bd9Sstevel@tonic-gate 	}
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
20587c478bd9Sstevel@tonic-gate 
2059a6469d9bSprasad 	/*
2060a6469d9bSprasad 	 * Note: Both non-prefetchable and prefetchable memory space
2061a6469d9bSprasad 	 * allocations are made within 32bit space. Currently, BIOSs
2062a6469d9bSprasad 	 * allocate device memory for PCI devices within the 32bit space
2063a6469d9bSprasad 	 * so this will not be a problem.
2064a6469d9bSprasad 	 */
2065a6469d9bSprasad 	request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED;
20667c478bd9Sstevel@tonic-gate 	request.ra_boundbase = 0;
20677c478bd9Sstevel@tonic-gate 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	rcount = length / sizeof (pci_regspec_t);
20707c478bd9Sstevel@tonic-gate 	offset = PCI_CONF_BASE0;
20717c478bd9Sstevel@tonic-gate 	for (i = 0; i < rcount; i++) {
2072a6469d9bSprasad 		char	*mem_type;
2073a6469d9bSprasad 
207426947304SEvan Yan 		if ((reg[i].pci_size_low != 0)|| (reg[i].pci_size_hi != 0)) {
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
20777c478bd9Sstevel@tonic-gate 			request.ra_len = reg[i].pci_size_low;
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
20807c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2081a6469d9bSprasad 				if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
208226947304SEvan Yan 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2083a6469d9bSprasad 				} else {
208426947304SEvan Yan 					mem_type = NDI_RA_TYPE_MEM;
2085a6469d9bSprasad 				}
20867c478bd9Sstevel@tonic-gate 				/* 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) {
20907c478bd9Sstevel@tonic-gate 					DEBUG0("Failed to allocate 64b mem\n");
20917c478bd9Sstevel@tonic-gate 					kmem_free(reg, length);
20927c478bd9Sstevel@tonic-gate 					(void) pcicfg_config_teardown(&handle);
20935af4ae46Sjveta 					return (PCICFG_NORESRC);
20947c478bd9Sstevel@tonic-gate 				}
2095a6469d9bSprasad 				DEBUG3("64 addr = [0x%x.0x%x] len [0x%x]\n",
209626947304SEvan Yan 				    PCICFG_HIADDR(answer),
209726947304SEvan Yan 				    PCICFG_LOADDR(answer), alen);
20987c478bd9Sstevel@tonic-gate 				/* program the low word */
209926947304SEvan Yan 				pci_config_put32(handle, offset,
210026947304SEvan Yan 				    PCICFG_LOADDR(answer));
2101a6469d9bSprasad 				/* program the high word */
21027c478bd9Sstevel@tonic-gate 				pci_config_put32(handle, offset + 4,
210326947304SEvan Yan 				    PCICFG_HIADDR(answer));
21047c478bd9Sstevel@tonic-gate 
2105a6469d9bSprasad 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
21067c478bd9Sstevel@tonic-gate 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
21077c478bd9Sstevel@tonic-gate 				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
210870025d76Sjohnny 				/*
210970025d76Sjohnny 				 * currently support 32b address space
211070025d76Sjohnny 				 * assignments only.
211170025d76Sjohnny 				 */
211226947304SEvan Yan 				reg[i].pci_phys_hi ^=
211326947304SEvan Yan 				    PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 				offset += 8;
21167c478bd9Sstevel@tonic-gate 				break;
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2119a6469d9bSprasad 				if (reg[i].pci_phys_hi & PCI_REG_PF_M)
2120a6469d9bSprasad 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2121a6469d9bSprasad 				else
2122a6469d9bSprasad 					mem_type = NDI_RA_TYPE_MEM;
21237c478bd9Sstevel@tonic-gate 				/* allocate memory space from the allocator */
212426947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
212526947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
212626947304SEvan Yan 				    != NDI_SUCCESS) {
21277c478bd9Sstevel@tonic-gate 					DEBUG0("Failed to allocate 32b mem\n");
21287c478bd9Sstevel@tonic-gate 					kmem_free(reg, length);
21297c478bd9Sstevel@tonic-gate 					(void) pcicfg_config_teardown(&handle);
21305af4ae46Sjveta 					return (PCICFG_NORESRC);
21317c478bd9Sstevel@tonic-gate 				}
2132a6469d9bSprasad 				DEBUG3("32 addr = [0x%x.0x%x] len [0x%x]\n",
213326947304SEvan Yan 				    PCICFG_HIADDR(answer),
213426947304SEvan Yan 				    PCICFG_LOADDR(answer),
213526947304SEvan Yan 				    alen);
21367c478bd9Sstevel@tonic-gate 				/* program the low word */
213726947304SEvan Yan 				pci_config_put32(handle, offset,
213826947304SEvan Yan 				    PCICFG_LOADDR(answer));
21397c478bd9Sstevel@tonic-gate 
2140a6469d9bSprasad 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
21417c478bd9Sstevel@tonic-gate 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
2142a6469d9bSprasad 				reg[i].pci_phys_mid = 0;
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 				offset += 4;
21457c478bd9Sstevel@tonic-gate 				break;
21467c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
2147b9abf428Slipeng sang - Sun Microsystems - Beijing China 				/*
2148b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * Try to allocate I/O space. If it fails,
2149b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * continue here instead of returning failure
2150b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * so that the hotplug for drivers that don't
2151b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * use I/O space can succeed, For drivers
2152b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * that need to use I/O space, the hotplug
2153b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 * will still fail later during driver attach.
2154b9abf428Slipeng sang - Sun Microsystems - Beijing China 				 */
215526947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
215626947304SEvan Yan 				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
215726947304SEvan Yan 				    != NDI_SUCCESS) {
21587c478bd9Sstevel@tonic-gate 					DEBUG0("Failed to allocate I/O\n");
2159b9abf428Slipeng sang - Sun Microsystems - Beijing China 					continue;
21607c478bd9Sstevel@tonic-gate 				}
2161a6469d9bSprasad 				DEBUG3("I/O addr = [0x%x.0x%x] len [0x%x]\n",
216226947304SEvan Yan 				    PCICFG_HIADDR(answer),
216326947304SEvan Yan 				    PCICFG_LOADDR(answer), alen);
216426947304SEvan Yan 				pci_config_put32(handle, offset,
216526947304SEvan Yan 				    PCICFG_LOADDR(answer));
21667c478bd9Sstevel@tonic-gate 
2167a6469d9bSprasad 				reg[i].pci_phys_hi |= PCI_REG_REL_M;
21687c478bd9Sstevel@tonic-gate 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate 				offset += 4;
21717c478bd9Sstevel@tonic-gate 				break;
21727c478bd9Sstevel@tonic-gate 			default:
21737c478bd9Sstevel@tonic-gate 				DEBUG0("Unknown register type\n");
21747c478bd9Sstevel@tonic-gate 				kmem_free(reg, length);
21757c478bd9Sstevel@tonic-gate 				(void) pcicfg_config_teardown(&handle);
21767c478bd9Sstevel@tonic-gate 				return (PCICFG_FAILURE);
21777c478bd9Sstevel@tonic-gate 			} /* switch */
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 			/*
21807c478bd9Sstevel@tonic-gate 			 * Now that memory locations are assigned,
21817c478bd9Sstevel@tonic-gate 			 * update the assigned address property.
21827c478bd9Sstevel@tonic-gate 			 */
21837c478bd9Sstevel@tonic-gate 
218426947304SEvan Yan 			if (pcicfg_update_assigned_prop(dip, &reg[i])
218526947304SEvan Yan 			    != PCICFG_SUCCESS) {
21867c478bd9Sstevel@tonic-gate 				kmem_free(reg, length);
21877c478bd9Sstevel@tonic-gate 				(void) pcicfg_config_teardown(&handle);
21887c478bd9Sstevel@tonic-gate 				return (PCICFG_FAILURE);
21897c478bd9Sstevel@tonic-gate 			}
21907c478bd9Sstevel@tonic-gate 		}
21917c478bd9Sstevel@tonic-gate 	}
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	(void) pcicfg_device_on(handle);
21947c478bd9Sstevel@tonic-gate 	kmem_free(reg, length);
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	PCICFG_DUMP_DEVICE_CONFIG(handle);
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 	(void) pcicfg_config_teardown(&handle);
21997c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
22007c478bd9Sstevel@tonic-gate }
22017c478bd9Sstevel@tonic-gate 
220226947304SEvan Yan static int
pcicfg_device_assign_readonly(dev_info_t * dip)220326947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip)
220426947304SEvan Yan {
220526947304SEvan Yan 	ddi_acc_handle_t	handle;
220626947304SEvan Yan 	pci_regspec_t		*assigned;
220726947304SEvan Yan 	int			length;
220826947304SEvan Yan 	int			acount;
220926947304SEvan Yan 	int			i;
221026947304SEvan Yan 	ndi_ra_request_t	request;
221126947304SEvan Yan 	uint64_t		answer;
221226947304SEvan Yan 	uint64_t		alen;
221326947304SEvan Yan 
221426947304SEvan Yan 	DEBUG1("%llx now under configuration\n", dip);
221526947304SEvan Yan 
221626947304SEvan Yan 	/*
221726947304SEvan Yan 	 * we don't support ntbridges for readonly probe.
221826947304SEvan Yan 	 */
221926947304SEvan Yan 	if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
222026947304SEvan Yan 		return (PCICFG_FAILURE);
222126947304SEvan Yan 	}
222226947304SEvan Yan 
222326947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
222426947304SEvan Yan 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
222526947304SEvan Yan 	    &length) != DDI_PROP_SUCCESS) {
222626947304SEvan Yan 		DEBUG0("Failed to read assigned-addresses property\n");
222726947304SEvan Yan 		return (PCICFG_FAILURE);
222826947304SEvan Yan 	}
222926947304SEvan Yan 
223026947304SEvan Yan 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
223126947304SEvan Yan 		DEBUG0("Failed to map config space!\n");
223226947304SEvan Yan 		kmem_free(assigned, length);
223326947304SEvan Yan 		return (PCICFG_FAILURE);
223426947304SEvan Yan 	}
223526947304SEvan Yan 
223626947304SEvan Yan 	/*
223726947304SEvan Yan 	 * If there is an interrupt pin set program
223826947304SEvan Yan 	 * interrupt line with default values.
223926947304SEvan Yan 	 */
224026947304SEvan Yan 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
224126947304SEvan Yan 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
224226947304SEvan Yan 	}
224326947304SEvan Yan 	/*
224426947304SEvan Yan 	 * Note: Both non-prefetchable and prefetchable memory space
224526947304SEvan Yan 	 * allocations are made within 32bit space. Currently, BIOSs
224626947304SEvan Yan 	 * allocate device memory for PCI devices within the 32bit space
224726947304SEvan Yan 	 * so this will not be a problem.
224826947304SEvan Yan 	 */
224926947304SEvan Yan 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
225026947304SEvan Yan 
225126947304SEvan Yan 	request.ra_flags = NDI_RA_ALLOC_SPECIFIED;  /* specified addr */
225226947304SEvan Yan 	request.ra_boundbase = 0;
225326947304SEvan Yan 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
225426947304SEvan Yan 
225526947304SEvan Yan 	acount = length / sizeof (pci_regspec_t);
225626947304SEvan Yan 	for (i = 0; i < acount; i++) {
225726947304SEvan Yan 		char	*mem_type;
225826947304SEvan Yan 
225926947304SEvan Yan 		if ((assigned[i].pci_size_low != 0)||
226026947304SEvan Yan 		    (assigned[i].pci_size_hi != 0)) {
226126947304SEvan Yan 
226226947304SEvan Yan 			request.ra_len = assigned[i].pci_size_low;
226326947304SEvan Yan 
226426947304SEvan Yan 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
226526947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
226626947304SEvan Yan 				request.ra_addr = (uint64_t)PCICFG_LADDR(
226726947304SEvan Yan 				    assigned[i].pci_phys_low,
226826947304SEvan Yan 				    assigned[i].pci_phys_mid);
226926947304SEvan Yan 
227026947304SEvan Yan 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M) {
227126947304SEvan Yan 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
227226947304SEvan Yan 				} else {
227326947304SEvan Yan 					mem_type = NDI_RA_TYPE_MEM;
227426947304SEvan Yan 				}
227526947304SEvan Yan 				/* allocate memory space from the allocator */
227626947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
227726947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
227826947304SEvan Yan 				    != NDI_SUCCESS) {
227926947304SEvan Yan 					DEBUG0("Failed to allocate 64b mem\n");
228026947304SEvan Yan 					kmem_free(assigned, length);
228126947304SEvan Yan 					return (PCICFG_NORESRC);
228226947304SEvan Yan 				}
228326947304SEvan Yan 
228426947304SEvan Yan 				break;
228526947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
228626947304SEvan Yan 				request.ra_addr = (uint64_t)
228726947304SEvan Yan 				    assigned[i].pci_phys_low;
228826947304SEvan Yan 
228926947304SEvan Yan 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
229026947304SEvan Yan 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
229126947304SEvan Yan 				else
229226947304SEvan Yan 					mem_type = NDI_RA_TYPE_MEM;
229326947304SEvan Yan 				/* allocate memory space from the allocator */
229426947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
229526947304SEvan Yan 				    &answer, &alen, mem_type, NDI_RA_PASS)
229626947304SEvan Yan 				    != NDI_SUCCESS) {
229726947304SEvan Yan 					DEBUG0("Failed to allocate 32b mem\n");
229826947304SEvan Yan 					kmem_free(assigned, length);
229926947304SEvan Yan 					return (PCICFG_NORESRC);
230026947304SEvan Yan 				}
230126947304SEvan Yan 
230226947304SEvan Yan 				break;
230326947304SEvan Yan 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
230426947304SEvan Yan 				request.ra_addr = (uint64_t)
230526947304SEvan Yan 				    assigned[i].pci_phys_low;
230626947304SEvan Yan 
230726947304SEvan Yan 				/* allocate I/O space from the allocator */
230826947304SEvan Yan 				if (ndi_ra_alloc(ddi_get_parent(dip), &request,
230926947304SEvan Yan 				    &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
231026947304SEvan Yan 				    != NDI_SUCCESS) {
231126947304SEvan Yan 					DEBUG0("Failed to allocate I/O\n");
231226947304SEvan Yan 					kmem_free(assigned, length);
231326947304SEvan Yan 					return (PCICFG_NORESRC);
231426947304SEvan Yan 				}
231526947304SEvan Yan 
231626947304SEvan Yan 				break;
231726947304SEvan Yan 			default:
231826947304SEvan Yan 				DEBUG0("Unknown register type\n");
231926947304SEvan Yan 				kmem_free(assigned, length);
232026947304SEvan Yan 				return (PCICFG_FAILURE);
232126947304SEvan Yan 			} /* switch */
232226947304SEvan Yan 		}
232326947304SEvan Yan 	}
232426947304SEvan Yan 
232526947304SEvan Yan 	(void) pcicfg_device_on(handle);
232626947304SEvan Yan 	kmem_free(assigned, length);
232726947304SEvan Yan 
232826947304SEvan Yan 	PCICFG_DUMP_DEVICE_CONFIG(handle);
232926947304SEvan Yan 
233026947304SEvan Yan 	(void) pcicfg_config_teardown(&handle);
233126947304SEvan Yan 	return (PCICFG_SUCCESS);
233226947304SEvan Yan }
233326947304SEvan Yan 
23347c478bd9Sstevel@tonic-gate #ifdef	DEBUG
23357c478bd9Sstevel@tonic-gate /*
23367c478bd9Sstevel@tonic-gate  * This function is useful in debug mode, where we can measure how
23377c478bd9Sstevel@tonic-gate  * much memory was wasted/unallocated in bridge device's domain.
23387c478bd9Sstevel@tonic-gate  */
23397c478bd9Sstevel@tonic-gate static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)23407c478bd9Sstevel@tonic-gate pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
23417c478bd9Sstevel@tonic-gate {
23427c478bd9Sstevel@tonic-gate 	uint64_t len = 0;
23437c478bd9Sstevel@tonic-gate 	uint32_t count = 0;
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 	do {
23467c478bd9Sstevel@tonic-gate 		len += hole->len;
23477c478bd9Sstevel@tonic-gate 		hole = hole->next;
23487c478bd9Sstevel@tonic-gate 		count++;
23497c478bd9Sstevel@tonic-gate 	} while (hole);
23507c478bd9Sstevel@tonic-gate 	*hole_count = count;
23517c478bd9Sstevel@tonic-gate 	return (len);
23527c478bd9Sstevel@tonic-gate }
23537c478bd9Sstevel@tonic-gate #endif
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate /*
23567c478bd9Sstevel@tonic-gate  * This function frees data structures that hold the hole information
23577c478bd9Sstevel@tonic-gate  * which are allocated in pcicfg_alloc_hole(). This is not freeing
23587c478bd9Sstevel@tonic-gate  * any memory allocated through NDI calls.
23597c478bd9Sstevel@tonic-gate  */
23607c478bd9Sstevel@tonic-gate static void
pcicfg_free_hole(hole_t * addr_hole)23617c478bd9Sstevel@tonic-gate pcicfg_free_hole(hole_t *addr_hole)
23627c478bd9Sstevel@tonic-gate {
23637c478bd9Sstevel@tonic-gate 	hole_t *nhole, *hole = addr_hole->next;
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 	while (hole) {
23667c478bd9Sstevel@tonic-gate 		nhole = hole->next;
23677c478bd9Sstevel@tonic-gate 		kmem_free(hole, sizeof (hole_t));
23687c478bd9Sstevel@tonic-gate 		hole = nhole;
23697c478bd9Sstevel@tonic-gate 	}
23707c478bd9Sstevel@tonic-gate }
23717c478bd9Sstevel@tonic-gate 
23727c478bd9Sstevel@tonic-gate static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)23737c478bd9Sstevel@tonic-gate pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
23747c478bd9Sstevel@tonic-gate {
23757c478bd9Sstevel@tonic-gate 	uint64_t actual_hole_start, ostart, olen;
23767c478bd9Sstevel@tonic-gate 	hole_t	*hole = addr_hole, *thole, *nhole;
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 	do {
23797c478bd9Sstevel@tonic-gate 		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
23807c478bd9Sstevel@tonic-gate 		if (((actual_hole_start - hole->start) + length) <= hole->len) {
2381a6469d9bSprasad 			DEBUG3("hole found. start %llx, len %llx, req=0x%x\n",
238226947304SEvan Yan 			    hole->start, hole->len, length);
23837c478bd9Sstevel@tonic-gate 			ostart = hole->start;
23847c478bd9Sstevel@tonic-gate 			olen = hole->len;
23857c478bd9Sstevel@tonic-gate 			/* current hole parameters adjust */
23867c478bd9Sstevel@tonic-gate 			if ((actual_hole_start - hole->start) == 0) {
23877c478bd9Sstevel@tonic-gate 				hole->start += length;
23887c478bd9Sstevel@tonic-gate 				hole->len -= length;
23897c478bd9Sstevel@tonic-gate 				if (hole->start > *alast)
23907c478bd9Sstevel@tonic-gate 					*alast = hole->start;
23917c478bd9Sstevel@tonic-gate 			} else {
23927c478bd9Sstevel@tonic-gate 				hole->len = actual_hole_start - hole->start;
23937c478bd9Sstevel@tonic-gate 				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
239426947304SEvan Yan 				    KM_SLEEP);
23957c478bd9Sstevel@tonic-gate 				nhole->start = actual_hole_start + length;
23967c478bd9Sstevel@tonic-gate 				nhole->len = (ostart + olen) - nhole->start;
23977c478bd9Sstevel@tonic-gate 				nhole->next = NULL;
23987c478bd9Sstevel@tonic-gate 				thole = hole->next;
23997c478bd9Sstevel@tonic-gate 				hole->next = nhole;
24007c478bd9Sstevel@tonic-gate 				nhole->next = thole;
24017c478bd9Sstevel@tonic-gate 				if (nhole->start > *alast)
24027c478bd9Sstevel@tonic-gate 					*alast = nhole->start;
24037c478bd9Sstevel@tonic-gate 				DEBUG2("put new hole to %llx, %llx\n",
240426947304SEvan Yan 				    nhole->start, nhole->len);
24057c478bd9Sstevel@tonic-gate 			}
24067c478bd9Sstevel@tonic-gate 			DEBUG2("adjust current hole to %llx, %llx\n",
240726947304SEvan Yan 			    hole->start, hole->len);
24087c478bd9Sstevel@tonic-gate 			break;
24097c478bd9Sstevel@tonic-gate 		}
24107c478bd9Sstevel@tonic-gate 		actual_hole_start = 0;
24117c478bd9Sstevel@tonic-gate 		hole = hole->next;
24127c478bd9Sstevel@tonic-gate 	} while (hole);
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	DEBUG1("return hole at %llx\n", actual_hole_start);
24157c478bd9Sstevel@tonic-gate 	return (actual_hole_start);
24167c478bd9Sstevel@tonic-gate }
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate static void
pcicfg_get_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)241926947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
24207c478bd9Sstevel@tonic-gate {
24217c478bd9Sstevel@tonic-gate 	uint64_t new_mem;
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 	/* See if there is a hole, that can hold this request. */
24247c478bd9Sstevel@tonic-gate 	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
242526947304SEvan Yan 	    length);
24267c478bd9Sstevel@tonic-gate 	if (new_mem) {	/* if non-zero, found a hole. */
24277c478bd9Sstevel@tonic-gate 		if (ans != NULL)
24287c478bd9Sstevel@tonic-gate 			*ans = new_mem;
24297c478bd9Sstevel@tonic-gate 	} else
24307c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
243126947304SEvan Yan 		    length, ddi_get_name(entry->dip));
24327c478bd9Sstevel@tonic-gate }
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate static void
pcicfg_get_io(pcicfg_phdl_t * entry,uint32_t length,uint32_t * ans)2435ffb64830SJordan Paige Hendricks pcicfg_get_io(pcicfg_phdl_t *entry, uint32_t length, uint32_t *ans)
24367c478bd9Sstevel@tonic-gate {
24377c478bd9Sstevel@tonic-gate 	uint32_t new_io;
24387c478bd9Sstevel@tonic-gate 	uint64_t io_last;
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	/*
24417c478bd9Sstevel@tonic-gate 	 * See if there is a hole, that can hold this request.
24427c478bd9Sstevel@tonic-gate 	 * Pass 64 bit parameters and then truncate to 32 bit.
24437c478bd9Sstevel@tonic-gate 	 */
24447c478bd9Sstevel@tonic-gate 	io_last = entry->io_last;
24457c478bd9Sstevel@tonic-gate 	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
24467c478bd9Sstevel@tonic-gate 	if (new_io) {	/* if non-zero, found a hole. */
24477c478bd9Sstevel@tonic-gate 		entry->io_last = (uint32_t)io_last;
24487c478bd9Sstevel@tonic-gate 		if (ans != NULL)
24497c478bd9Sstevel@tonic-gate 			*ans = new_io;
24507c478bd9Sstevel@tonic-gate 	} else
24517c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
245226947304SEvan Yan 		    length, ddi_get_name(entry->dip));
24537c478bd9Sstevel@tonic-gate }
24547c478bd9Sstevel@tonic-gate 
2455a6469d9bSprasad static void
pcicfg_get_pf_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)245626947304SEvan Yan pcicfg_get_pf_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
2457a6469d9bSprasad {
2458a6469d9bSprasad 	uint64_t new_mem;
2459a6469d9bSprasad 
2460a6469d9bSprasad 	/* See if there is a hole, that can hold this request. */
2461a6469d9bSprasad 	new_mem = pcicfg_alloc_hole(&entry->pf_mem_hole, &entry->pf_memory_last,
246226947304SEvan Yan 	    length);
2463a6469d9bSprasad 	if (new_mem) {	/* if non-zero, found a hole. */
2464a6469d9bSprasad 		if (ans != NULL)
2465a6469d9bSprasad 			*ans = new_mem;
2466a6469d9bSprasad 	} else
2467a6469d9bSprasad 		cmn_err(CE_WARN, "No %u bytes PF memory window for %s\n",
246826947304SEvan Yan 		    length, ddi_get_name(entry->dip));
2469a6469d9bSprasad }
2470a6469d9bSprasad 
2471ae5a8bedSAndy Fiddaman #ifdef __sparc
24727c478bd9Sstevel@tonic-gate static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)24737c478bd9Sstevel@tonic-gate pcicfg_sum_resources(dev_info_t *dip, void *hdl)
24747c478bd9Sstevel@tonic-gate {
24757c478bd9Sstevel@tonic-gate 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
24767c478bd9Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
24777c478bd9Sstevel@tonic-gate 	int length;
24787c478bd9Sstevel@tonic-gate 	int rcount;
24797c478bd9Sstevel@tonic-gate 	int i;
2480a6469d9bSprasad 	ndi_ra_request_t *pf_mem_request;
24817c478bd9Sstevel@tonic-gate 	ndi_ra_request_t *mem_request;
24827c478bd9Sstevel@tonic-gate 	ndi_ra_request_t *io_request;
24837c478bd9Sstevel@tonic-gate 	uint8_t header_type;
24847c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t handle;
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	entry->error = PCICFG_SUCCESS;
24877c478bd9Sstevel@tonic-gate 
2488a6469d9bSprasad 	pf_mem_request = &entry->pf_mem_req;
24897c478bd9Sstevel@tonic-gate 	mem_request = &entry->mem_req;
24907c478bd9Sstevel@tonic-gate 	io_request =  &entry->io_req;
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
24937c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to map config space!\n");
24947c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
24957c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
24967c478bd9Sstevel@tonic-gate 	}
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 	/*
25017c478bd9Sstevel@tonic-gate 	 * If its a bridge - just record the highest bus seen
25027c478bd9Sstevel@tonic-gate 	 */
25037c478bd9Sstevel@tonic-gate 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 		if (entry->highest_bus < pci_config_get8(handle,
250626947304SEvan Yan 		    PCI_BCNF_SECBUS)) {
25077c478bd9Sstevel@tonic-gate 			entry->highest_bus =
250826947304SEvan Yan 			    pci_config_get8(handle, PCI_BCNF_SECBUS);
25097c478bd9Sstevel@tonic-gate 		}
25107c478bd9Sstevel@tonic-gate 		(void) pcicfg_config_teardown(&handle);
25117c478bd9Sstevel@tonic-gate 		entry->error = PCICFG_FAILURE;
25127c478bd9Sstevel@tonic-gate 		return (DDI_WALK_CONTINUE);
25137c478bd9Sstevel@tonic-gate 	} else {
251426947304SEvan Yan 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
251526947304SEvan Yan 		    "reg", (caddr_t)&pci_rp, &length) != DDI_PROP_SUCCESS) {
25167c478bd9Sstevel@tonic-gate 			/*
25177c478bd9Sstevel@tonic-gate 			 * If one node in (the subtree of nodes)
25187c478bd9Sstevel@tonic-gate 			 * doesn't have a "reg" property fail the
25197c478bd9Sstevel@tonic-gate 			 * allocation.
25207c478bd9Sstevel@tonic-gate 			 */
25217c478bd9Sstevel@tonic-gate 			entry->memory_len = 0;
25227c478bd9Sstevel@tonic-gate 			entry->io_len = 0;
2523a6469d9bSprasad 			entry->pf_memory_len = 0;
25247c478bd9Sstevel@tonic-gate 			entry->error = PCICFG_FAILURE;
25251fb5b786Sprasad 			(void) pcicfg_config_teardown(&handle);
25267c478bd9Sstevel@tonic-gate 			return (DDI_WALK_TERMINATE);
25277c478bd9Sstevel@tonic-gate 		}
25287c478bd9Sstevel@tonic-gate 		/*
25297c478bd9Sstevel@tonic-gate 		 * For each "reg" property with a length, add that to the
25307c478bd9Sstevel@tonic-gate 		 * total memory (or I/O) to allocate.
25317c478bd9Sstevel@tonic-gate 		 */
25327c478bd9Sstevel@tonic-gate 		rcount = length / sizeof (pci_regspec_t);
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 		for (i = 0; i < rcount; i++) {
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2539a6469d9bSprasad 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
254026947304SEvan Yan 					pf_mem_request->ra_len =
254126947304SEvan Yan 					    pci_rp[i].pci_size_low +
254226947304SEvan Yan 					    PCICFG_ROUND_UP(
254326947304SEvan Yan 					    pf_mem_request->ra_len,
254426947304SEvan Yan 					    pci_rp[i].pci_size_low);
254526947304SEvan Yan 					DEBUG1("ADDING 32 --->0x%x\n",
254626947304SEvan Yan 					    pci_rp[i].pci_size_low);
2547a6469d9bSprasad 				} else {
254826947304SEvan Yan 					mem_request->ra_len =
254926947304SEvan Yan 					    pci_rp[i].pci_size_low +
255026947304SEvan Yan 					    PCICFG_ROUND_UP(mem_request->ra_len,
255126947304SEvan Yan 					    pci_rp[i].pci_size_low);
255226947304SEvan Yan 					DEBUG1("ADDING 32 --->0x%x\n",
255326947304SEvan Yan 					    pci_rp[i].pci_size_low);
2554a6469d9bSprasad 				}
25557c478bd9Sstevel@tonic-gate 
255626947304SEvan Yan 				break;
25577c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2558a6469d9bSprasad 				if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
255926947304SEvan Yan 					pf_mem_request->ra_len =
256026947304SEvan Yan 					    pci_rp[i].pci_size_low +
256126947304SEvan Yan 					    PCICFG_ROUND_UP(
256226947304SEvan Yan 					    pf_mem_request->ra_len,
256326947304SEvan Yan 					    pci_rp[i].pci_size_low);
256426947304SEvan Yan 					DEBUG1("ADDING 64 --->0x%x\n",
256526947304SEvan Yan 					    pci_rp[i].pci_size_low);
2566a6469d9bSprasad 				} else {
256726947304SEvan Yan 					mem_request->ra_len =
256826947304SEvan Yan 					    pci_rp[i].pci_size_low +
256926947304SEvan Yan 					    PCICFG_ROUND_UP(mem_request->ra_len,
257026947304SEvan Yan 					    pci_rp[i].pci_size_low);
257126947304SEvan Yan 					DEBUG1("ADDING 64 --->0x%x\n",
257226947304SEvan Yan 					    pci_rp[i].pci_size_low);
2573a6469d9bSprasad 				}
25747c478bd9Sstevel@tonic-gate 
257526947304SEvan Yan 				break;
25767c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
25777c478bd9Sstevel@tonic-gate 				io_request->ra_len =
257826947304SEvan Yan 				    pci_rp[i].pci_size_low +
257926947304SEvan Yan 				    PCICFG_ROUND_UP(io_request->ra_len,
258026947304SEvan Yan 				    pci_rp[i].pci_size_low);
25817c478bd9Sstevel@tonic-gate 				DEBUG1("ADDING I/O --->0x%x\n",
258226947304SEvan Yan 				    pci_rp[i].pci_size_low);
258326947304SEvan Yan 				break;
25847c478bd9Sstevel@tonic-gate 			default:
258526947304SEvan Yan 				/* Config space register - not included */
258626947304SEvan Yan 				break;
25877c478bd9Sstevel@tonic-gate 			}
25887c478bd9Sstevel@tonic-gate 		}
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 		/*
25917c478bd9Sstevel@tonic-gate 		 * free the memory allocated by ddi_getlongprop
25927c478bd9Sstevel@tonic-gate 		 */
25937c478bd9Sstevel@tonic-gate 		kmem_free(pci_rp, length);
25947c478bd9Sstevel@tonic-gate 
25957c478bd9Sstevel@tonic-gate 		/*
25967c478bd9Sstevel@tonic-gate 		 * continue the walk to the next sibling to sum memory
25977c478bd9Sstevel@tonic-gate 		 */
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate 		(void) pcicfg_config_teardown(&handle);
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 		return (DDI_WALK_CONTINUE);
26027c478bd9Sstevel@tonic-gate 	}
26037c478bd9Sstevel@tonic-gate }
2604ae5a8bedSAndy Fiddaman #endif /* __sparc */
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate static int
pcicfg_free_bridge_resources(dev_info_t * dip)26077c478bd9Sstevel@tonic-gate pcicfg_free_bridge_resources(dev_info_t *dip)
26087c478bd9Sstevel@tonic-gate {
260900d0963fSdilpreet 	ppb_ranges_t		*ranges;
26107c478bd9Sstevel@tonic-gate 	uint_t			*bus;
26117c478bd9Sstevel@tonic-gate 	int			k;
26121fb5b786Sprasad 	int			length = 0;
26137c478bd9Sstevel@tonic-gate 	int			i;
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 
261626947304SEvan Yan 	if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
261726947304SEvan Yan 	    "ranges", (caddr_t)&ranges, &length)) != DDI_PROP_SUCCESS) {
26187c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to read ranges property\n");
261970025d76Sjohnny 		if (ddi_get_child(dip)) {
262070025d76Sjohnny 			cmn_err(CE_WARN, "No ranges property found for %s",
262126947304SEvan Yan 			    ddi_get_name(dip));
262270025d76Sjohnny 			/*
262370025d76Sjohnny 			 * strictly speaking, we can check for children with
262470025d76Sjohnny 			 * assigned-addresses but for now it is better to
262570025d76Sjohnny 			 * be conservative and assume that if there are child
262670025d76Sjohnny 			 * nodes, then they do consume PCI memory or IO
262770025d76Sjohnny 			 * resources, Hence return failure.
262870025d76Sjohnny 			 */
262970025d76Sjohnny 			return (PCICFG_FAILURE);
263070025d76Sjohnny 		}
263170025d76Sjohnny 		length = 0;
26327c478bd9Sstevel@tonic-gate 	}
26337c478bd9Sstevel@tonic-gate 
263400d0963fSdilpreet 	for (i = 0; i < length / sizeof (ppb_ranges_t); i++) {
2635a6469d9bSprasad 		char *mem_type;
2636a6469d9bSprasad 
263726947304SEvan Yan 		if (ranges[i].size_low != 0 || ranges[i].size_high != 0) {
263800d0963fSdilpreet 			switch (ranges[i].parent_high & PCI_REG_ADDR_M) {
263926947304SEvan Yan 			case PCI_ADDR_IO:
264026947304SEvan Yan 				DEBUG2("Free I/O    base/length = "
264126947304SEvan Yan 				    "[0x%x]/[0x%x]\n", ranges[i].child_low,
264226947304SEvan Yan 				    ranges[i].size_low);
264326947304SEvan Yan 				if (ndi_ra_free(ddi_get_parent(dip),
264426947304SEvan Yan 				    (uint64_t)ranges[i].child_low,
264526947304SEvan Yan 				    (uint64_t)ranges[i].size_low,
264626947304SEvan Yan 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
264726947304SEvan Yan 				    != NDI_SUCCESS) {
264826947304SEvan Yan 					DEBUG0("Trouble freeing "
264926947304SEvan Yan 					    "PCI i/o space\n");
265026947304SEvan Yan 					kmem_free(ranges, length);
265126947304SEvan Yan 					return (PCICFG_FAILURE);
265226947304SEvan Yan 				}
26537c478bd9Sstevel@tonic-gate 				break;
265426947304SEvan Yan 			case PCI_ADDR_MEM32:
265526947304SEvan Yan 			case PCI_ADDR_MEM64:
265626947304SEvan Yan 				if (ranges[i].parent_high & PCI_REG_PF_M) {
265726947304SEvan Yan 					DEBUG3("Free PF Memory base/length = "
265826947304SEvan Yan 					    "[0x%x.0x%x]/[0x%x]\n",
265926947304SEvan Yan 					    ranges[i].child_mid,
266026947304SEvan Yan 					    ranges[i].child_low,
266126947304SEvan Yan 					    ranges[i].size_low);
2662a6469d9bSprasad 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
266326947304SEvan Yan 				} else {
2664a6469d9bSprasad 					DEBUG3("Free Memory base/length"
266526947304SEvan Yan 					    " = [0x%x.0x%x]/[0x%x]\n",
266626947304SEvan Yan 					    ranges[i].child_mid,
266726947304SEvan Yan 					    ranges[i].child_low,
266826947304SEvan Yan 					    ranges[i].size_low)
2669a6469d9bSprasad 					mem_type = NDI_RA_TYPE_MEM;
267026947304SEvan Yan 				}
267126947304SEvan Yan 				if (ndi_ra_free(ddi_get_parent(dip),
267226947304SEvan Yan 				    PCICFG_LADDR(ranges[i].child_low,
267326947304SEvan Yan 				    ranges[i].child_mid),
267426947304SEvan Yan 				    (uint64_t)ranges[i].size_low,
267526947304SEvan Yan 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
267626947304SEvan Yan 					DEBUG0("Trouble freeing "
267726947304SEvan Yan 					    "PCI memory space\n");
267826947304SEvan Yan 					kmem_free(ranges, length);
267926947304SEvan Yan 					return (PCICFG_FAILURE);
268026947304SEvan Yan 				}
26817c478bd9Sstevel@tonic-gate 				break;
268226947304SEvan Yan 			default:
268326947304SEvan Yan 				DEBUG0("Unknown memory space\n");
26847c478bd9Sstevel@tonic-gate 				break;
26857c478bd9Sstevel@tonic-gate 			}
26867c478bd9Sstevel@tonic-gate 		}
26877c478bd9Sstevel@tonic-gate 	}
26887c478bd9Sstevel@tonic-gate 
268970025d76Sjohnny 	if (length)
269070025d76Sjohnny 		kmem_free(ranges, length);
26917c478bd9Sstevel@tonic-gate 
269226947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
269326947304SEvan Yan 	    "bus-range", (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
26947c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to read bus-range property\n");
26957c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
26967c478bd9Sstevel@tonic-gate 	}
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate 	DEBUG2("Need to free bus [%d] range [%d]\n",
269926947304SEvan Yan 	    bus[0], bus[1] - bus[0] + 1);
27007c478bd9Sstevel@tonic-gate 
270126947304SEvan Yan 	if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
270226947304SEvan Yan 	    (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
270326947304SEvan Yan 	    NDI_RA_PASS) != NDI_SUCCESS) {
27047c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to free a bus number\n");
27051fb5b786Sprasad 		kmem_free(bus, k);
27067c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
27077c478bd9Sstevel@tonic-gate 	}
27081fb5b786Sprasad 
27091fb5b786Sprasad 	kmem_free(bus, k);
27107c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
27117c478bd9Sstevel@tonic-gate }
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate static int
pcicfg_free_device_resources(dev_info_t * dip)27147c478bd9Sstevel@tonic-gate pcicfg_free_device_resources(dev_info_t *dip)
27157c478bd9Sstevel@tonic-gate {
27167c478bd9Sstevel@tonic-gate 	pci_regspec_t *assigned;
27177c478bd9Sstevel@tonic-gate 
27187c478bd9Sstevel@tonic-gate 	int length;
27197c478bd9Sstevel@tonic-gate 	int acount;
27207c478bd9Sstevel@tonic-gate 	int i;
27217c478bd9Sstevel@tonic-gate 
272226947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
272326947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &length)
272426947304SEvan Yan 	    != DDI_PROP_SUCCESS) {
27257c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to read assigned-addresses property\n");
27267c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
27277c478bd9Sstevel@tonic-gate 	}
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate 	/*
27307c478bd9Sstevel@tonic-gate 	 * For each "assigned-addresses" property entry with a length,
27317c478bd9Sstevel@tonic-gate 	 * call the memory allocation routines to return the
27327c478bd9Sstevel@tonic-gate 	 * resource.
27337c478bd9Sstevel@tonic-gate 	 */
27347c478bd9Sstevel@tonic-gate 	acount = length / sizeof (pci_regspec_t);
27357c478bd9Sstevel@tonic-gate 	for (i = 0; i < acount; i++) {
2736a6469d9bSprasad 		char *mem_type;
2737a6469d9bSprasad 
27387c478bd9Sstevel@tonic-gate 		/*
27397c478bd9Sstevel@tonic-gate 		 * Free the resource if the size of it is not zero.
27407c478bd9Sstevel@tonic-gate 		 */
27417c478bd9Sstevel@tonic-gate 		if ((assigned[i].pci_size_low != 0)||
274226947304SEvan Yan 		    (assigned[i].pci_size_hi != 0)) {
27437c478bd9Sstevel@tonic-gate 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
27447c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
27457c478bd9Sstevel@tonic-gate 				/*
27467c478bd9Sstevel@tonic-gate 				 * Check the assigned address for zero.
27477c478bd9Sstevel@tonic-gate 				 * (Workaround for Devconf (x86) bug to
27487c478bd9Sstevel@tonic-gate 				 * skip bogus entry for ROM base address
27497c478bd9Sstevel@tonic-gate 				 * register. If the assigned address is
27507c478bd9Sstevel@tonic-gate 				 * zero then ignore the entry
27517c478bd9Sstevel@tonic-gate 				 * (see bugid 4281306)).
27527c478bd9Sstevel@tonic-gate 				 */
27537c478bd9Sstevel@tonic-gate 				if (assigned[i].pci_phys_low == 0)
27547c478bd9Sstevel@tonic-gate 					break; /* ignore the entry */
27557c478bd9Sstevel@tonic-gate 
2756a6469d9bSprasad 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
2757a6469d9bSprasad 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2758a6469d9bSprasad 				else
2759a6469d9bSprasad 					mem_type = NDI_RA_TYPE_MEM;
2760a6469d9bSprasad 
27617c478bd9Sstevel@tonic-gate 				if (ndi_ra_free(ddi_get_parent(dip),
27621fb5b786Sprasad 				    (uint64_t)assigned[i].pci_phys_low,
27631fb5b786Sprasad 				    (uint64_t)assigned[i].pci_size_low,
27641fb5b786Sprasad 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
27651fb5b786Sprasad 					DEBUG0("Trouble freeing "
276626947304SEvan Yan 					    "PCI memory space\n");
27671fb5b786Sprasad 					kmem_free(assigned, length);
27681fb5b786Sprasad 					return (PCICFG_FAILURE);
27697c478bd9Sstevel@tonic-gate 				}
27707c478bd9Sstevel@tonic-gate 
2771a6469d9bSprasad 				DEBUG4("Returned 0x%x of 32 bit %s space"
277226947304SEvan Yan 				    " @ 0x%x from register 0x%x\n",
277326947304SEvan Yan 				    assigned[i].pci_size_low, mem_type,
277426947304SEvan Yan 				    assigned[i].pci_phys_low,
277526947304SEvan Yan 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
27767c478bd9Sstevel@tonic-gate 
27777c478bd9Sstevel@tonic-gate 			break;
27787c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2779a6469d9bSprasad 				if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
2780a6469d9bSprasad 					mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2781a6469d9bSprasad 				else
2782a6469d9bSprasad 					mem_type = NDI_RA_TYPE_MEM;
2783a6469d9bSprasad 
27847c478bd9Sstevel@tonic-gate 				if (ndi_ra_free(ddi_get_parent(dip),
27851fb5b786Sprasad 				    PCICFG_LADDR(assigned[i].pci_phys_low,
27861fb5b786Sprasad 				    assigned[i].pci_phys_mid),
27871fb5b786Sprasad 				    (uint64_t)assigned[i].pci_size_low,
27881fb5b786Sprasad 				    mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
27891fb5b786Sprasad 					DEBUG0("Trouble freeing "
279026947304SEvan Yan 					    "PCI memory space\n");
27911fb5b786Sprasad 					kmem_free(assigned, length);
27921fb5b786Sprasad 					return (PCICFG_FAILURE);
27937c478bd9Sstevel@tonic-gate 				}
27947c478bd9Sstevel@tonic-gate 
2795a6469d9bSprasad 				DEBUG5("Returned 0x%x of 64 bit %s space"
279626947304SEvan Yan 				    " @ 0x%x.0x%x from register 0x%x\n",
279726947304SEvan Yan 				    assigned[i].pci_size_low,
279826947304SEvan Yan 				    mem_type, assigned[i].pci_phys_mid,
279926947304SEvan Yan 				    assigned[i].pci_phys_low,
280026947304SEvan Yan 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 			break;
28037c478bd9Sstevel@tonic-gate 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
28047c478bd9Sstevel@tonic-gate 				if (ndi_ra_free(ddi_get_parent(dip),
28051fb5b786Sprasad 				    (uint64_t)assigned[i].pci_phys_low,
28061fb5b786Sprasad 				    (uint64_t)assigned[i].pci_size_low,
28071fb5b786Sprasad 				    NDI_RA_TYPE_IO, NDI_RA_PASS) !=
28081fb5b786Sprasad 				    NDI_SUCCESS) {
28091fb5b786Sprasad 					DEBUG0("Trouble freeing "
281026947304SEvan Yan 					    "PCI IO space\n");
28111fb5b786Sprasad 					kmem_free(assigned, length);
28121fb5b786Sprasad 					return (PCICFG_FAILURE);
28137c478bd9Sstevel@tonic-gate 				}
281426947304SEvan Yan 				DEBUG3("Returned 0x%x of IO space @ 0x%x from "
281526947304SEvan Yan 				    "register 0x%x\n", assigned[i].pci_size_low,
281626947304SEvan Yan 				    assigned[i].pci_phys_low,
281726947304SEvan Yan 				    PCI_REG_REG_G(assigned[i].pci_phys_hi));
28187c478bd9Sstevel@tonic-gate 			break;
28197c478bd9Sstevel@tonic-gate 			default:
28207c478bd9Sstevel@tonic-gate 				DEBUG0("Unknown register type\n");
28217c478bd9Sstevel@tonic-gate 				kmem_free(assigned, length);
28227c478bd9Sstevel@tonic-gate 				return (PCICFG_FAILURE);
28237c478bd9Sstevel@tonic-gate 			} /* switch */
28247c478bd9Sstevel@tonic-gate 		}
28257c478bd9Sstevel@tonic-gate 	}
28267c478bd9Sstevel@tonic-gate 	kmem_free(assigned, length);
28277c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
28287c478bd9Sstevel@tonic-gate }
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate static int
pcicfg_free_resources(dev_info_t * dip,pcicfg_flags_t flags)283126947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
28327c478bd9Sstevel@tonic-gate {
28337c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t handle;
28347c478bd9Sstevel@tonic-gate 	uint8_t header_type;
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
28377c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to map config space!\n");
28387c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
28397c478bd9Sstevel@tonic-gate 	}
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 	(void) pci_config_teardown(&handle);
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate 	/*
28467c478bd9Sstevel@tonic-gate 	 * A different algorithm is used for bridges and leaf devices.
28477c478bd9Sstevel@tonic-gate 	 */
28487c478bd9Sstevel@tonic-gate 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
284926947304SEvan Yan 		/*
285026947304SEvan Yan 		 * We only support readonly probing for leaf devices.
285126947304SEvan Yan 		 */
285226947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
285326947304SEvan Yan 			return (PCICFG_FAILURE);
285426947304SEvan Yan 
28557c478bd9Sstevel@tonic-gate 		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
28567c478bd9Sstevel@tonic-gate 			DEBUG0("Failed freeing up bridge resources\n");
28577c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
28587c478bd9Sstevel@tonic-gate 		}
28597c478bd9Sstevel@tonic-gate 	} else {
28607c478bd9Sstevel@tonic-gate 		if (pcicfg_free_device_resources(dip) != PCICFG_SUCCESS) {
28617c478bd9Sstevel@tonic-gate 			DEBUG0("Failed freeing up device resources\n");
28627c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
28637c478bd9Sstevel@tonic-gate 		}
28647c478bd9Sstevel@tonic-gate 	}
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
28677c478bd9Sstevel@tonic-gate }
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate #ifndef _DONT_USE_1275_GENERIC_NAMES
28707c478bd9Sstevel@tonic-gate static char *
pcicfg_get_class_name(uint32_t classcode)28717c478bd9Sstevel@tonic-gate pcicfg_get_class_name(uint32_t classcode)
28727c478bd9Sstevel@tonic-gate {
28737c478bd9Sstevel@tonic-gate 	struct pcicfg_name_entry *ptr;
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate 	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
28767c478bd9Sstevel@tonic-gate 		if (ptr->class_code == classcode) {
28777c478bd9Sstevel@tonic-gate 			return (ptr->name);
28787c478bd9Sstevel@tonic-gate 		}
28797c478bd9Sstevel@tonic-gate 	}
28807c478bd9Sstevel@tonic-gate 	return (NULL);
28817c478bd9Sstevel@tonic-gate }
28827c478bd9Sstevel@tonic-gate #endif /* _DONT_USE_1275_GENERIC_NAMES */
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)28857c478bd9Sstevel@tonic-gate pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
28867c478bd9Sstevel@tonic-gate {
28877c478bd9Sstevel@tonic-gate 	struct pcicfg_find_ctrl ctrl;
28887c478bd9Sstevel@tonic-gate 
28897c478bd9Sstevel@tonic-gate 	ctrl.device = device;
28907c478bd9Sstevel@tonic-gate 	ctrl.function = function;
28917c478bd9Sstevel@tonic-gate 	ctrl.dip = NULL;
28927c478bd9Sstevel@tonic-gate 
28933fe80ca4SDan Cross 	ndi_devi_enter(dip);
28947c478bd9Sstevel@tonic-gate 	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
28953fe80ca4SDan Cross 	ndi_devi_exit(dip);
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate 	return (ctrl.dip);
28987c478bd9Sstevel@tonic-gate }
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)29017c478bd9Sstevel@tonic-gate pcicfg_match_dev(dev_info_t *dip, void *hdl)
29027c478bd9Sstevel@tonic-gate {
29037c478bd9Sstevel@tonic-gate 	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
29047c478bd9Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
29057c478bd9Sstevel@tonic-gate 	int length;
29067c478bd9Sstevel@tonic-gate 	int pci_dev;
29077c478bd9Sstevel@tonic-gate 	int pci_func;
29087c478bd9Sstevel@tonic-gate 
290926947304SEvan Yan 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
291026947304SEvan Yan 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
29117c478bd9Sstevel@tonic-gate 		ctrl->dip = NULL;
29127c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
29137c478bd9Sstevel@tonic-gate 	}
29147c478bd9Sstevel@tonic-gate 
29157c478bd9Sstevel@tonic-gate 	/* get the PCI device address info */
29167c478bd9Sstevel@tonic-gate 	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
29177c478bd9Sstevel@tonic-gate 	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
29187c478bd9Sstevel@tonic-gate 
29197c478bd9Sstevel@tonic-gate 	/*
29207c478bd9Sstevel@tonic-gate 	 * free the memory allocated by ddi_prop_lookup_int_array
29217c478bd9Sstevel@tonic-gate 	 */
29227c478bd9Sstevel@tonic-gate 	ddi_prop_free(pci_rp);
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
29267c478bd9Sstevel@tonic-gate 		/* found the match for the specified device address */
29277c478bd9Sstevel@tonic-gate 		ctrl->dip = dip;
29287c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
29297c478bd9Sstevel@tonic-gate 	}
29307c478bd9Sstevel@tonic-gate 
29317c478bd9Sstevel@tonic-gate 	/*
29327c478bd9Sstevel@tonic-gate 	 * continue the walk to the next sibling to look for a match.
29337c478bd9Sstevel@tonic-gate 	 */
29347c478bd9Sstevel@tonic-gate 	return (DDI_WALK_PRUNECHILD);
29357c478bd9Sstevel@tonic-gate }
29367c478bd9Sstevel@tonic-gate 
29377c478bd9Sstevel@tonic-gate static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)29387c478bd9Sstevel@tonic-gate pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
29397c478bd9Sstevel@tonic-gate {
29407c478bd9Sstevel@tonic-gate 	int		alen;
29417c478bd9Sstevel@tonic-gate 	pci_regspec_t	*assigned;
29427c478bd9Sstevel@tonic-gate 	caddr_t		newreg;
29437c478bd9Sstevel@tonic-gate 	uint_t		status;
29447c478bd9Sstevel@tonic-gate 
2945a3282898Scth 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
294626947304SEvan Yan 	    "assigned-addresses", (caddr_t)&assigned, &alen);
29477c478bd9Sstevel@tonic-gate 	switch (status) {
29487c478bd9Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
29497c478bd9Sstevel@tonic-gate 		break;
29507c478bd9Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
29517c478bd9Sstevel@tonic-gate 			DEBUG0("no memory for assigned-addresses property\n");
29527c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
29537c478bd9Sstevel@tonic-gate 		default:
29547c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
295526947304SEvan Yan 			    "assigned-addresses", (int *)newone,
295626947304SEvan Yan 			    sizeof (*newone)/sizeof (int));
29577c478bd9Sstevel@tonic-gate 			return (PCICFG_SUCCESS);
29587c478bd9Sstevel@tonic-gate 	}
29597c478bd9Sstevel@tonic-gate 
29607c478bd9Sstevel@tonic-gate 	/*
29617c478bd9Sstevel@tonic-gate 	 * Allocate memory for the existing
29627c478bd9Sstevel@tonic-gate 	 * assigned-addresses(s) plus one and then
29637c478bd9Sstevel@tonic-gate 	 * build it.
29647c478bd9Sstevel@tonic-gate 	 */
29657c478bd9Sstevel@tonic-gate 
29667c478bd9Sstevel@tonic-gate 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
29677c478bd9Sstevel@tonic-gate 
29687c478bd9Sstevel@tonic-gate 	bcopy(assigned, newreg, alen);
29697c478bd9Sstevel@tonic-gate 	bcopy(newone, newreg + alen, sizeof (*newone));
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	/*
29727c478bd9Sstevel@tonic-gate 	 * Write out the new "assigned-addresses" spec
29737c478bd9Sstevel@tonic-gate 	 */
29747c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
297526947304SEvan Yan 	    "assigned-addresses", (int *)newreg,
297626947304SEvan Yan 	    (alen + sizeof (*newone))/sizeof (int));
29777c478bd9Sstevel@tonic-gate 
29787c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
29797c478bd9Sstevel@tonic-gate 	kmem_free(assigned, alen);
29807c478bd9Sstevel@tonic-gate 
29817c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
29827c478bd9Sstevel@tonic-gate }
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate static int
pcicfg_update_ranges_prop(dev_info_t * dip,ppb_ranges_t * addition)298500d0963fSdilpreet pcicfg_update_ranges_prop(dev_info_t *dip, ppb_ranges_t *addition)
29867c478bd9Sstevel@tonic-gate {
29877c478bd9Sstevel@tonic-gate 	int		rlen;
298800d0963fSdilpreet 	ppb_ranges_t	*ranges;
29897c478bd9Sstevel@tonic-gate 	caddr_t		newreg;
29907c478bd9Sstevel@tonic-gate 	uint_t		status;
29917c478bd9Sstevel@tonic-gate 
299226947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
299326947304SEvan Yan 	    "ranges", (caddr_t)&ranges, &rlen);
29947c478bd9Sstevel@tonic-gate 
29957c478bd9Sstevel@tonic-gate 
29967c478bd9Sstevel@tonic-gate 	switch (status) {
29977c478bd9Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
2998a6469d9bSprasad 			break;
29997c478bd9Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
30007c478bd9Sstevel@tonic-gate 			DEBUG0("ranges present, but unable to get memory\n");
30017c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
30027c478bd9Sstevel@tonic-gate 		default:
30037c478bd9Sstevel@tonic-gate 			DEBUG0("no ranges property - creating one\n");
30047c478bd9Sstevel@tonic-gate 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
300526947304SEvan Yan 			    dip, "ranges", (int *)addition,
300626947304SEvan Yan 			    sizeof (ppb_ranges_t)/sizeof (int))
300726947304SEvan Yan 			    != DDI_SUCCESS) {
30087c478bd9Sstevel@tonic-gate 				DEBUG0("Did'nt create ranges property\n");
30097c478bd9Sstevel@tonic-gate 				return (PCICFG_FAILURE);
30107c478bd9Sstevel@tonic-gate 			}
30117c478bd9Sstevel@tonic-gate 			return (PCICFG_SUCCESS);
30127c478bd9Sstevel@tonic-gate 	}
30137c478bd9Sstevel@tonic-gate 
30147c478bd9Sstevel@tonic-gate 	/*
3015a6469d9bSprasad 	 * Allocate memory for the existing ranges plus one and then
30167c478bd9Sstevel@tonic-gate 	 * build it.
30177c478bd9Sstevel@tonic-gate 	 */
301800d0963fSdilpreet 	newreg = kmem_zalloc(rlen+sizeof (ppb_ranges_t), KM_SLEEP);
30197c478bd9Sstevel@tonic-gate 
30207c478bd9Sstevel@tonic-gate 	bcopy(ranges, newreg, rlen);
302100d0963fSdilpreet 	bcopy(addition, newreg + rlen, sizeof (ppb_ranges_t));
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 	/*
30247c478bd9Sstevel@tonic-gate 	 * Write out the new "ranges" property
30257c478bd9Sstevel@tonic-gate 	 */
302626947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
302726947304SEvan Yan 	    (int *)newreg, (rlen + sizeof (ppb_ranges_t))/sizeof (int));
30287c478bd9Sstevel@tonic-gate 
3029a6469d9bSprasad 	DEBUG1("Updating ranges property for %d entries",
303026947304SEvan Yan 	    rlen / sizeof (ppb_ranges_t) + 1);
3031a6469d9bSprasad 
303200d0963fSdilpreet 	kmem_free((caddr_t)newreg, rlen+sizeof (ppb_ranges_t));
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)ranges, rlen);
30357c478bd9Sstevel@tonic-gate 
30367c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
30377c478bd9Sstevel@tonic-gate }
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)30407c478bd9Sstevel@tonic-gate pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
30417c478bd9Sstevel@tonic-gate {
30427c478bd9Sstevel@tonic-gate 	int		rlen;
30437c478bd9Sstevel@tonic-gate 	pci_regspec_t	*reg;
30447c478bd9Sstevel@tonic-gate 	caddr_t		newreg;
30457c478bd9Sstevel@tonic-gate 	uint32_t	hiword;
30467c478bd9Sstevel@tonic-gate 	pci_regspec_t	addition;
30477c478bd9Sstevel@tonic-gate 	uint32_t	size;
30487c478bd9Sstevel@tonic-gate 	uint_t		status;
30497c478bd9Sstevel@tonic-gate 
3050a3282898Scth 	status = ddi_getlongprop(DDI_DEV_T_ANY,
305126947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 	switch (status) {
30547c478bd9Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
30557c478bd9Sstevel@tonic-gate 		break;
30567c478bd9Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
30577c478bd9Sstevel@tonic-gate 			DEBUG0("reg present, but unable to get memory\n");
30587c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
30597c478bd9Sstevel@tonic-gate 		default:
30607c478bd9Sstevel@tonic-gate 			DEBUG0("no reg property\n");
30617c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
30627c478bd9Sstevel@tonic-gate 	}
30637c478bd9Sstevel@tonic-gate 
30647c478bd9Sstevel@tonic-gate 	/*
30657c478bd9Sstevel@tonic-gate 	 * Allocate memory for the existing reg(s) plus one and then
30667c478bd9Sstevel@tonic-gate 	 * build it.
30677c478bd9Sstevel@tonic-gate 	 */
30687c478bd9Sstevel@tonic-gate 	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
30697c478bd9Sstevel@tonic-gate 
30707c478bd9Sstevel@tonic-gate 	/*
30717c478bd9Sstevel@tonic-gate 	 * Build the regspec, then add it to the existing one(s)
30727c478bd9Sstevel@tonic-gate 	 */
30737c478bd9Sstevel@tonic-gate 
30747c478bd9Sstevel@tonic-gate 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
30757c478bd9Sstevel@tonic-gate 	    PCI_REG_DEV_G(reg->pci_phys_hi),
30767c478bd9Sstevel@tonic-gate 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
30777c478bd9Sstevel@tonic-gate 
30787c478bd9Sstevel@tonic-gate 	if (reg_offset == PCI_CONF_ROM) {
30797c478bd9Sstevel@tonic-gate 		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
30807c478bd9Sstevel@tonic-gate 		hiword |= PCI_ADDR_MEM32;
30817c478bd9Sstevel@tonic-gate 	} else {
30827c478bd9Sstevel@tonic-gate 		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
30857c478bd9Sstevel@tonic-gate 			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
30867c478bd9Sstevel@tonic-gate 				hiword |= PCI_ADDR_MEM32;
30877c478bd9Sstevel@tonic-gate 			} else if ((PCI_BASE_TYPE_M & regvalue)
308826947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
30897c478bd9Sstevel@tonic-gate 				hiword |= PCI_ADDR_MEM64;
30907c478bd9Sstevel@tonic-gate 			}
3091a6469d9bSprasad 			if (regvalue & PCI_BASE_PREF_M)
3092a6469d9bSprasad 				hiword |= PCI_REG_PF_M;
30937c478bd9Sstevel@tonic-gate 		} else {
30947c478bd9Sstevel@tonic-gate 			hiword |= PCI_ADDR_IO;
30957c478bd9Sstevel@tonic-gate 		}
30967c478bd9Sstevel@tonic-gate 	}
30977c478bd9Sstevel@tonic-gate 
30987c478bd9Sstevel@tonic-gate 	addition.pci_phys_hi = hiword;
30997c478bd9Sstevel@tonic-gate 	addition.pci_phys_mid = 0;
31007c478bd9Sstevel@tonic-gate 	addition.pci_phys_low = 0;
31017c478bd9Sstevel@tonic-gate 	addition.pci_size_hi = 0;
31027c478bd9Sstevel@tonic-gate 	addition.pci_size_low = size;
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 	bcopy(reg, newreg, rlen);
31057c478bd9Sstevel@tonic-gate 	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
31067c478bd9Sstevel@tonic-gate 
310770025d76Sjohnny 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
31087c478bd9Sstevel@tonic-gate 	/*
31097c478bd9Sstevel@tonic-gate 	 * Write out the new "reg" property
31107c478bd9Sstevel@tonic-gate 	 */
311126947304SEvan Yan 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
311226947304SEvan Yan 	    (int *)newreg, (rlen + sizeof (pci_regspec_t))/sizeof (int));
31137c478bd9Sstevel@tonic-gate 
31147c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
31157c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)reg, rlen);
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
31187c478bd9Sstevel@tonic-gate }
31197c478bd9Sstevel@tonic-gate 
312026947304SEvan Yan static int
pcicfg_update_assigned_prop_value(dev_info_t * dip,uint32_t size,uint32_t base,uint32_t base_hi,uint_t reg_offset)312126947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
312226947304SEvan Yan     uint32_t base, uint32_t base_hi, uint_t reg_offset)
312326947304SEvan Yan {
312426947304SEvan Yan 	int		rlen;
312526947304SEvan Yan 	pci_regspec_t	*reg;
312626947304SEvan Yan 	uint32_t	hiword;
312726947304SEvan Yan 	pci_regspec_t	addition;
312826947304SEvan Yan 	uint_t		status;
312926947304SEvan Yan 
313026947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY,
313126947304SEvan Yan 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
313226947304SEvan Yan 
313326947304SEvan Yan 	switch (status) {
313426947304SEvan Yan 		case DDI_PROP_SUCCESS:
313526947304SEvan Yan 		break;
313626947304SEvan Yan 		case DDI_PROP_NO_MEMORY:
313726947304SEvan Yan 			DEBUG0("reg present, but unable to get memory\n");
313826947304SEvan Yan 			return (PCICFG_FAILURE);
313926947304SEvan Yan 		default:
314026947304SEvan Yan 			/*
314126947304SEvan Yan 			 * Since the config space "reg" entry should have been
314226947304SEvan Yan 			 * created, we expect a "reg" property already
314326947304SEvan Yan 			 * present here.
314426947304SEvan Yan 			 */
314526947304SEvan Yan 			DEBUG0("no reg property\n");
314626947304SEvan Yan 			return (PCICFG_FAILURE);
314726947304SEvan Yan 	}
314826947304SEvan Yan 
314926947304SEvan Yan 	/*
315026947304SEvan Yan 	 * Build the regspec, then add it to the existing one(s)
315126947304SEvan Yan 	 */
315226947304SEvan Yan 
315326947304SEvan Yan 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
315426947304SEvan Yan 	    PCI_REG_DEV_G(reg->pci_phys_hi),
315526947304SEvan Yan 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
315626947304SEvan Yan 
315726947304SEvan Yan 	hiword |= PCI_REG_REL_M;
315826947304SEvan Yan 
315926947304SEvan Yan 	if (reg_offset == PCI_CONF_ROM) {
316026947304SEvan Yan 		hiword |= PCI_ADDR_MEM32;
316126947304SEvan Yan 
316226947304SEvan Yan 		base = PCI_BASE_ROM_ADDR_M & base;
316326947304SEvan Yan 	} else {
316426947304SEvan Yan 		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
316526947304SEvan Yan 			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
316626947304SEvan Yan 				hiword |= PCI_ADDR_MEM32;
316726947304SEvan Yan 			} else if ((PCI_BASE_TYPE_M & base)
316826947304SEvan Yan 			    == PCI_BASE_TYPE_ALL) {
316926947304SEvan Yan 				hiword |= PCI_ADDR_MEM64;
317026947304SEvan Yan 			}
317126947304SEvan Yan 			if (base & PCI_BASE_PREF_M)
317226947304SEvan Yan 				hiword |= PCI_REG_PF_M;
317326947304SEvan Yan 
317426947304SEvan Yan 			base = PCI_BASE_M_ADDR_M & base;
317526947304SEvan Yan 		} else {
317626947304SEvan Yan 			hiword |= PCI_ADDR_IO;
317726947304SEvan Yan 
317826947304SEvan Yan 			base = PCI_BASE_IO_ADDR_M & base;
317926947304SEvan Yan 			base_hi = 0;
318026947304SEvan Yan 		}
318126947304SEvan Yan 	}
318226947304SEvan Yan 
318326947304SEvan Yan 	addition.pci_phys_hi = hiword;
318426947304SEvan Yan 	addition.pci_phys_mid = base_hi;
318526947304SEvan Yan 	addition.pci_phys_low = base;
318626947304SEvan Yan 	addition.pci_size_hi = 0;
318726947304SEvan Yan 	addition.pci_size_low = size;
318826947304SEvan Yan 
318926947304SEvan Yan 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
319026947304SEvan Yan 
319126947304SEvan Yan 	kmem_free((caddr_t)reg, rlen);
319226947304SEvan Yan 
319326947304SEvan Yan 	return (pcicfg_update_assigned_prop(dip, &addition));
319426947304SEvan Yan }
319526947304SEvan Yan 
31967c478bd9Sstevel@tonic-gate static void
pcicfg_device_on(ddi_acc_handle_t config_handle)31977c478bd9Sstevel@tonic-gate pcicfg_device_on(ddi_acc_handle_t config_handle)
31987c478bd9Sstevel@tonic-gate {
31997c478bd9Sstevel@tonic-gate 	/*
32007c478bd9Sstevel@tonic-gate 	 * Enable memory, IO, and bus mastership
32017c478bd9Sstevel@tonic-gate 	 * XXX should we enable parity, SERR#,
32027c478bd9Sstevel@tonic-gate 	 * fast back-to-back, and addr. stepping?
32037c478bd9Sstevel@tonic-gate 	 */
32047c478bd9Sstevel@tonic-gate 	pci_config_put16(config_handle, PCI_CONF_COMM,
320526947304SEvan Yan 	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
32067c478bd9Sstevel@tonic-gate }
32077c478bd9Sstevel@tonic-gate 
32087c478bd9Sstevel@tonic-gate static void
pcicfg_device_off(ddi_acc_handle_t config_handle)32097c478bd9Sstevel@tonic-gate pcicfg_device_off(ddi_acc_handle_t config_handle)
32107c478bd9Sstevel@tonic-gate {
32117c478bd9Sstevel@tonic-gate 	/*
32127c478bd9Sstevel@tonic-gate 	 * Disable I/O and memory traffic through the bridge
32137c478bd9Sstevel@tonic-gate 	 */
32147c478bd9Sstevel@tonic-gate 	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
32157c478bd9Sstevel@tonic-gate }
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type)321870025d76Sjohnny pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type)
32197c478bd9Sstevel@tonic-gate {
32207c478bd9Sstevel@tonic-gate 	int ret;
322170025d76Sjohnny 	char device_type[8];
322270025d76Sjohnny 
322370025d76Sjohnny 	if (pcie_device_type)
322470025d76Sjohnny 		(void) strcpy(device_type, "pciex");
322570025d76Sjohnny 	else
322670025d76Sjohnny 		(void) strcpy(device_type, "pci");
32277c478bd9Sstevel@tonic-gate 
32287c478bd9Sstevel@tonic-gate 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
322926947304SEvan Yan 	    "device_type", device_type)) != DDI_SUCCESS) {
32307c478bd9Sstevel@tonic-gate 		return (ret);
32317c478bd9Sstevel@tonic-gate 	}
32327c478bd9Sstevel@tonic-gate 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
323326947304SEvan Yan 	    "#address-cells", 3)) != DDI_SUCCESS) {
32347c478bd9Sstevel@tonic-gate 		return (ret);
32357c478bd9Sstevel@tonic-gate 	}
323626947304SEvan Yan 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 2))
323726947304SEvan Yan 	    != DDI_SUCCESS) {
32387c478bd9Sstevel@tonic-gate 		return (ret);
32397c478bd9Sstevel@tonic-gate 	}
32407c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
32417c478bd9Sstevel@tonic-gate }
32427c478bd9Sstevel@tonic-gate 
32437c478bd9Sstevel@tonic-gate /*
32447c478bd9Sstevel@tonic-gate  * Program the bus numbers into the bridge
32457c478bd9Sstevel@tonic-gate  */
32467c478bd9Sstevel@tonic-gate static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,uint_t primary,uint_t secondary,uint_t subordinate)3247ffb64830SJordan Paige Hendricks pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle, uint_t primary,
3248ffb64830SJordan Paige Hendricks     uint_t secondary, uint_t subordinate)
32497c478bd9Sstevel@tonic-gate {
325070025d76Sjohnny 	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
325126947304SEvan Yan 	    subordinate);
32527c478bd9Sstevel@tonic-gate 	/*
32537c478bd9Sstevel@tonic-gate 	 * Primary bus#
32547c478bd9Sstevel@tonic-gate 	 */
32557c478bd9Sstevel@tonic-gate 	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 	/*
32587c478bd9Sstevel@tonic-gate 	 * Secondary bus#
32597c478bd9Sstevel@tonic-gate 	 */
32607c478bd9Sstevel@tonic-gate 	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 	/*
32637c478bd9Sstevel@tonic-gate 	 * Set the subordinate bus number to ff in order to pass through any
32647c478bd9Sstevel@tonic-gate 	 * type 1 cycle with a bus number higher than the secondary bus#
32657c478bd9Sstevel@tonic-gate 	 */
326670025d76Sjohnny 	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
32677c478bd9Sstevel@tonic-gate }
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate /*
32707c478bd9Sstevel@tonic-gate  * Put bridge registers into initial state
32717c478bd9Sstevel@tonic-gate  */
32727c478bd9Sstevel@tonic-gate static void
pcicfg_setup_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)3273ffb64830SJordan Paige Hendricks pcicfg_setup_bridge(pcicfg_phdl_t *entry, ddi_acc_handle_t handle)
32747c478bd9Sstevel@tonic-gate {
32757c478bd9Sstevel@tonic-gate 	/*
32767c478bd9Sstevel@tonic-gate 	 * The highest bus seen during probing is the max-subordinate bus
32777c478bd9Sstevel@tonic-gate 	 */
32787c478bd9Sstevel@tonic-gate 	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
32797c478bd9Sstevel@tonic-gate 
32807c478bd9Sstevel@tonic-gate 	/*
32817c478bd9Sstevel@tonic-gate 	 * Reset the secondary bus
32827c478bd9Sstevel@tonic-gate 	 */
32837c478bd9Sstevel@tonic-gate 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
328426947304SEvan Yan 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
328570025d76Sjohnny 	drv_usecwait(1000);
32867c478bd9Sstevel@tonic-gate 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
328726947304SEvan Yan 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
328870025d76Sjohnny 	drv_usecwait(1000);
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate 	/*
32917c478bd9Sstevel@tonic-gate 	 * Program the memory base register with the
32927c478bd9Sstevel@tonic-gate 	 * start of the memory range
32937c478bd9Sstevel@tonic-gate 	 */
32947c478bd9Sstevel@tonic-gate 	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
329526947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate 	/*
32987c478bd9Sstevel@tonic-gate 	 * Program the I/O base register with the start of the I/O range
32997c478bd9Sstevel@tonic-gate 	 */
33007c478bd9Sstevel@tonic-gate 	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
330126947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
33027c478bd9Sstevel@tonic-gate 	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
330326947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
33047c478bd9Sstevel@tonic-gate 
33057c478bd9Sstevel@tonic-gate 	/*
3306a6469d9bSprasad 	 * Program the PF memory base register with the start of
3307a6469d9bSprasad 	 * PF memory range
33087c478bd9Sstevel@tonic-gate 	 */
3309a6469d9bSprasad 	pci_config_put16(handle, PCI_BCNF_PF_BASE_LOW,
331026947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
3311a6469d9bSprasad 	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH,
331226947304SEvan Yan 	    PCICFG_HIADDR(entry->pf_memory_last));
33137c478bd9Sstevel@tonic-gate 
33147c478bd9Sstevel@tonic-gate 	/*
3315a6469d9bSprasad 	 * Clear status bits
33167c478bd9Sstevel@tonic-gate 	 */
3317a6469d9bSprasad 	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate 	/*
33207c478bd9Sstevel@tonic-gate 	 * Needs to be set to this value
33217c478bd9Sstevel@tonic-gate 	 */
33227c478bd9Sstevel@tonic-gate 	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
332370025d76Sjohnny 
332470025d76Sjohnny 	/*
332570025d76Sjohnny 	 * XXX - may be delay should be used since noone configures
332670025d76Sjohnny 	 * devices in the interrupt context
332770025d76Sjohnny 	 */
332870025d76Sjohnny 	drv_usecwait(pcicfg_sec_reset_delay);	/* 1 sec wait */
33297c478bd9Sstevel@tonic-gate }
33307c478bd9Sstevel@tonic-gate 
33317c478bd9Sstevel@tonic-gate static void
pcicfg_update_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)3332ffb64830SJordan Paige Hendricks pcicfg_update_bridge(pcicfg_phdl_t *entry, ddi_acc_handle_t handle)
33337c478bd9Sstevel@tonic-gate {
33347c478bd9Sstevel@tonic-gate 	uint_t length;
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate 	/*
33377c478bd9Sstevel@tonic-gate 	 * Program the memory limit register with the end of the memory range
33387c478bd9Sstevel@tonic-gate 	 */
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
334126947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN));
33427c478bd9Sstevel@tonic-gate 
33437c478bd9Sstevel@tonic-gate 	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
334426947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(
334526947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN))));
33467c478bd9Sstevel@tonic-gate 	/*
33477c478bd9Sstevel@tonic-gate 	 * Since this is a bridge, the rest of this range will
33487c478bd9Sstevel@tonic-gate 	 * be responded to by the bridge.  We have to round up
33497c478bd9Sstevel@tonic-gate 	 * so no other device claims it.
33507c478bd9Sstevel@tonic-gate 	 */
335126947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN)
335226947304SEvan Yan 	    - entry->memory_last)) > 0) {
33537c478bd9Sstevel@tonic-gate 		(void) pcicfg_get_mem(entry, length, NULL);
335426947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (mem)\n", length);
33557c478bd9Sstevel@tonic-gate 	}
33567c478bd9Sstevel@tonic-gate 
3357a6469d9bSprasad 	/*
3358a6469d9bSprasad 	 * Program the PF memory limit register with the end of the memory range
3359a6469d9bSprasad 	 */
3360a6469d9bSprasad 
3361a6469d9bSprasad 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
336226947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN));
3363a6469d9bSprasad 
3364a6469d9bSprasad 	pci_config_put16(handle, PCI_BCNF_PF_LIMIT_LOW,
336526947304SEvan Yan 	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(
336626947304SEvan Yan 	    entry->pf_memory_last, PCICFG_MEMGRAN))));
336726947304SEvan Yan 	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, PCICFG_HIADDR(
336826947304SEvan Yan 	    PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN)));
336926947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->pf_memory_last, PCICFG_MEMGRAN)
337026947304SEvan Yan 	    - entry->pf_memory_last)) > 0) {
3371a6469d9bSprasad 		(void) pcicfg_get_pf_mem(entry, length, NULL);
337226947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (PF mem)\n",
337326947304SEvan Yan 		    length);
3374a6469d9bSprasad 	}
3375a6469d9bSprasad 
33767c478bd9Sstevel@tonic-gate 	/*
33777c478bd9Sstevel@tonic-gate 	 * Program the I/O limit register with the end of the I/O range
33787c478bd9Sstevel@tonic-gate 	 */
33797c478bd9Sstevel@tonic-gate 	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
338026947304SEvan Yan 	    PCICFG_HIBYTE(PCICFG_LOWORD(
338126947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN)))));
33827c478bd9Sstevel@tonic-gate 
338326947304SEvan Yan 	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, PCICFG_HIWORD(
338426947304SEvan Yan 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN))));
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 	/*
33877c478bd9Sstevel@tonic-gate 	 * Same as above for I/O space. Since this is a
33887c478bd9Sstevel@tonic-gate 	 * bridge, the rest of this range will be responded
33897c478bd9Sstevel@tonic-gate 	 * to by the bridge.  We have to round up so no
33907c478bd9Sstevel@tonic-gate 	 * other device claims it.
33917c478bd9Sstevel@tonic-gate 	 */
339226947304SEvan Yan 	if ((length = (PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN)
339326947304SEvan Yan 	    - entry->io_last)) > 0) {
33947c478bd9Sstevel@tonic-gate 		(void) pcicfg_get_io(entry, length, NULL);
339526947304SEvan Yan 		DEBUG1("Added [0x%x]at the top of the bridge (I/O)\n", length);
33967c478bd9Sstevel@tonic-gate 	}
33977c478bd9Sstevel@tonic-gate }
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate static int
pcicfg_probe_children(dev_info_t * parent,uint_t bus,uint_t device,uint_t func,uint_t * highest_bus,pcicfg_flags_t flags,boolean_t is_pcie)340026947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
3401c0da6274SZhi-Jun Robin Fu     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
34027c478bd9Sstevel@tonic-gate {
34037c478bd9Sstevel@tonic-gate 	dev_info_t		*new_child;
34047c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	config_handle;
34055af4ae46Sjveta 	int			ret = PCICFG_FAILURE;
3406*bd97c7ceSRobert Mustacchi 	pci_prop_data_t		prop_data;
3407*bd97c7ceSRobert Mustacchi 	pci_prop_failure_t	prop_ret;
34087c478bd9Sstevel@tonic-gate 
34097c478bd9Sstevel@tonic-gate 	/*
34107c478bd9Sstevel@tonic-gate 	 * This node will be put immediately below
34117c478bd9Sstevel@tonic-gate 	 * "parent". Allocate a blank device node.  It will either
34127c478bd9Sstevel@tonic-gate 	 * be filled in or freed up based on further probing.
34137c478bd9Sstevel@tonic-gate 	 */
34147c478bd9Sstevel@tonic-gate 
34157c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(parent, DEVI_PSEUDO_NEXNAME,
341626947304SEvan Yan 	    (pnode_t)DEVI_SID_NODEID, &new_child);
34177c478bd9Sstevel@tonic-gate 
341826947304SEvan Yan 	if (pcicfg_add_config_reg(new_child, bus, device, func)
341926947304SEvan Yan 	    != DDI_SUCCESS) {
342026947304SEvan Yan 		DEBUG0("pcicfg_probe_children():Failed to add candidate REG\n");
342170025d76Sjohnny 		goto failedconfig;
34227c478bd9Sstevel@tonic-gate 	}
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 	if ((ret = pcicfg_config_setup(new_child, &config_handle))
342526947304SEvan Yan 	    != PCICFG_SUCCESS) {
34267c478bd9Sstevel@tonic-gate 		if (ret == PCICFG_NODEVICE) {
34277c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(new_child);
34287c478bd9Sstevel@tonic-gate 			return (ret);
34297c478bd9Sstevel@tonic-gate 		}
34307c478bd9Sstevel@tonic-gate 		DEBUG0("pcicfg_probe_children():"
34317c478bd9Sstevel@tonic-gate 		"Failed to setup config space\n");
34327c478bd9Sstevel@tonic-gate 		goto failedconfig;
34337c478bd9Sstevel@tonic-gate 	}
34347c478bd9Sstevel@tonic-gate 
3435c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3436c0da6274SZhi-Jun Robin Fu 		(void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
3437c0da6274SZhi-Jun Robin Fu 		    PCIE_BUS_INITIAL);
3438c0da6274SZhi-Jun Robin Fu 
34397c478bd9Sstevel@tonic-gate 	/*
34407c478bd9Sstevel@tonic-gate 	 * As soon as we have access to config space,
34417c478bd9Sstevel@tonic-gate 	 * turn off device. It will get turned on
34427c478bd9Sstevel@tonic-gate 	 * later (after memory is assigned).
34437c478bd9Sstevel@tonic-gate 	 */
34447c478bd9Sstevel@tonic-gate 	(void) pcicfg_device_off(config_handle);
34457c478bd9Sstevel@tonic-gate 
3446*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_data_fill(config_handle, bus, device, func,
3447*bd97c7ceSRobert Mustacchi 	    &prop_data);
3448*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3449*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to get basic PCI data for "
3450*bd97c7ceSRobert Mustacchi 		    "b/d/f 0x%x/0x%x/0x%x: 0x%x", bus, device, func, prop_ret);
3451*bd97c7ceSRobert Mustacchi 		goto failedchild;
345270025d76Sjohnny 	}
345370025d76Sjohnny 
3454*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_name_node(new_child, &prop_data);
3455*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3456*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to set node name for b/d/f "
3457*bd97c7ceSRobert Mustacchi 		    "0x%x/0x%x/0x%x: 0x%x", bus,
3458*bd97c7ceSRobert Mustacchi 		    device, func, prop_ret);
34597c478bd9Sstevel@tonic-gate 		goto failedchild;
34607c478bd9Sstevel@tonic-gate 	}
34617c478bd9Sstevel@tonic-gate 
3462*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_set_common_props(new_child, &prop_data);
3463*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3464*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to set properties for b/d/f "
3465*bd97c7ceSRobert Mustacchi 		    "0x%x/0x%x/0x%x: 0x%x", bus,
3466*bd97c7ceSRobert Mustacchi 		    device, func, prop_ret);
34677c478bd9Sstevel@tonic-gate 		goto failedchild;
34687c478bd9Sstevel@tonic-gate 	}
34697c478bd9Sstevel@tonic-gate 
3470*bd97c7ceSRobert Mustacchi 	prop_ret = pci_prop_set_compatible(new_child, &prop_data);
3471*bd97c7ceSRobert Mustacchi 	if (prop_ret != PCI_PROP_OK) {
3472*bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "hotplug: failed to set compatible property "
3473*bd97c7ceSRobert Mustacchi 		    "for b/d/f 0x%x/0x%x/0x%x: 0x%x",
3474*bd97c7ceSRobert Mustacchi 		    bus, device, func, prop_ret);
3475*bd97c7ceSRobert Mustacchi 		goto failedchild;
3476*bd97c7ceSRobert Mustacchi 	}
34777c478bd9Sstevel@tonic-gate 
34787c478bd9Sstevel@tonic-gate 	/*
34797c478bd9Sstevel@tonic-gate 	 * If this is not a multi-function card only probe function zero.
34807c478bd9Sstevel@tonic-gate 	 */
3481*bd97c7ceSRobert Mustacchi 	if ((prop_data.ppd_flags & PCI_PROP_F_MULT_FUNC) == 0 && func != 0) {
34827c478bd9Sstevel@tonic-gate 
3483c0da6274SZhi-Jun Robin Fu 		ret = PCICFG_NODEVICE;
3484c0da6274SZhi-Jun Robin Fu 		goto failedchild;
34857c478bd9Sstevel@tonic-gate 	}
34867c478bd9Sstevel@tonic-gate 
348770025d76Sjohnny 	/*
348870025d76Sjohnny 	 * Attach the child to its parent
348970025d76Sjohnny 	 */
349070025d76Sjohnny 	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
349170025d76Sjohnny 
34923a634bfcSVikram Hegde 	DEVI_SET_PCI(new_child);
34933a634bfcSVikram Hegde 
3494*bd97c7ceSRobert Mustacchi 	if (prop_data.ppd_header == PCI_HEADER_PPB) {
34957c478bd9Sstevel@tonic-gate 
349626947304SEvan Yan 		DEBUG3("--Bridge found bus [0x%x] device[0x%x] func [0x%x]\n",
349726947304SEvan Yan 		    bus, device, func);
349826947304SEvan Yan 
349926947304SEvan Yan 		/* Only support read-only probe for leaf device */
350026947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY)
350126947304SEvan Yan 			goto failedchild;
35027c478bd9Sstevel@tonic-gate 
35035af4ae46Sjveta 		ret = pcicfg_probe_bridge(new_child, config_handle, bus,
3504c0da6274SZhi-Jun Robin Fu 		    highest_bus, is_pcie);
35055af4ae46Sjveta 		if (ret != PCICFG_SUCCESS) {
350670025d76Sjohnny 			(void) pcicfg_free_bridge_resources(new_child);
35077c478bd9Sstevel@tonic-gate 			goto failedchild;
35087c478bd9Sstevel@tonic-gate 		}
35097c478bd9Sstevel@tonic-gate 
35107c478bd9Sstevel@tonic-gate 	} else {
35117c478bd9Sstevel@tonic-gate 
35127c478bd9Sstevel@tonic-gate 		DEBUG3("--Leaf device found bus [0x%x] device"
351326947304SEvan Yan 		    "[0x%x] func [0x%x]\n", bus, device, func);
35147c478bd9Sstevel@tonic-gate 
351526947304SEvan Yan 		if (flags & PCICFG_FLAG_READ_ONLY) {
351626947304SEvan Yan 			/*
351726947304SEvan Yan 			 * with read-only probe, don't do any resource
351826947304SEvan Yan 			 * allocation, just read the BARs and update props.
351926947304SEvan Yan 			 */
352026947304SEvan Yan 			ret = pcicfg_populate_props_from_bar(new_child,
352126947304SEvan Yan 			    config_handle);
352226947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
352326947304SEvan Yan 				goto failedchild;
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 			/*
352626947304SEvan Yan 			 * now allocate the resources, just remove the
352726947304SEvan Yan 			 * resources from the parent busra pool.
35287c478bd9Sstevel@tonic-gate 			 */
352926947304SEvan Yan 			ret = pcicfg_device_assign_readonly(new_child);
353026947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
353126947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child);
353226947304SEvan Yan 				goto failedchild;
35337c478bd9Sstevel@tonic-gate 			}
35347c478bd9Sstevel@tonic-gate 
353526947304SEvan Yan 		} else {
35367c478bd9Sstevel@tonic-gate 			/*
353726947304SEvan Yan 			 * update "reg" property by sizing the BARs.
35387c478bd9Sstevel@tonic-gate 			 */
353926947304SEvan Yan 			ret = pcicfg_populate_reg_props(new_child,
354026947304SEvan Yan 			    config_handle);
354126947304SEvan Yan 			if (ret != PCICFG_SUCCESS)
354226947304SEvan Yan 				goto failedchild;
354326947304SEvan Yan 
354426947304SEvan Yan 			/* now allocate & program the resources */
354526947304SEvan Yan 			ret = pcicfg_device_assign(new_child);
354626947304SEvan Yan 			if (ret != PCICFG_SUCCESS) {
354726947304SEvan Yan 				(void) pcicfg_free_device_resources(new_child);
354826947304SEvan Yan 				goto failedchild;
35497c478bd9Sstevel@tonic-gate 			}
35507c478bd9Sstevel@tonic-gate 		}
35517c478bd9Sstevel@tonic-gate 
355226947304SEvan Yan 		(void) ndi_devi_bind_driver(new_child, 0);
355326947304SEvan Yan 	}
355426947304SEvan Yan 
355526947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
355626947304SEvan Yan 
3557c0da6274SZhi-Jun Robin Fu 	/*
3558c0da6274SZhi-Jun Robin Fu 	 * Properties have been setted up, so initialize the remaining
3559c0da6274SZhi-Jun Robin Fu 	 * bus_t fields
3560c0da6274SZhi-Jun Robin Fu 	 */
3561c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3562c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
3563c0da6274SZhi-Jun Robin Fu 
356426947304SEvan Yan 	return (PCICFG_SUCCESS);
356526947304SEvan Yan 
356626947304SEvan Yan failedchild:
356726947304SEvan Yan 	/*
356826947304SEvan Yan 	 * XXX check if it should be taken offline (if online)
356926947304SEvan Yan 	 */
357026947304SEvan Yan 	(void) pcicfg_config_teardown(&config_handle);
357126947304SEvan Yan 
3572c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
3573c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_FINAL);
3574c0da6274SZhi-Jun Robin Fu 
357526947304SEvan Yan failedconfig:
357626947304SEvan Yan 
357726947304SEvan Yan 	(void) ndi_devi_free(new_child);
357826947304SEvan Yan 	return (ret);
357926947304SEvan Yan }
358026947304SEvan Yan 
358126947304SEvan Yan /*
358226947304SEvan Yan  * Sizing the BARs and update "reg" property
358326947304SEvan Yan  */
358426947304SEvan Yan static int
pcicfg_populate_reg_props(dev_info_t * new_child,ddi_acc_handle_t config_handle)3585ffb64830SJordan Paige Hendricks pcicfg_populate_reg_props(dev_info_t *new_child, ddi_acc_handle_t config_handle)
358626947304SEvan Yan {
358726947304SEvan Yan 	int		i;
3588ffb64830SJordan Paige Hendricks 	uint32_t	request;
35897c478bd9Sstevel@tonic-gate 
359026947304SEvan Yan 	i = PCI_CONF_BASE0;
359126947304SEvan Yan 
359226947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
359326947304SEvan Yan 
359426947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
359526947304SEvan Yan 
359626947304SEvan Yan 		request = pci_config_get32(config_handle, i);
35977c478bd9Sstevel@tonic-gate 		/*
35987c478bd9Sstevel@tonic-gate 		 * If its a zero length, don't do
35997c478bd9Sstevel@tonic-gate 		 * any programming.
36007c478bd9Sstevel@tonic-gate 		 */
36017c478bd9Sstevel@tonic-gate 		if (request != 0) {
36027c478bd9Sstevel@tonic-gate 			/*
36037c478bd9Sstevel@tonic-gate 			 * Add to the "reg" property
36047c478bd9Sstevel@tonic-gate 			 */
36057c478bd9Sstevel@tonic-gate 			if (pcicfg_update_reg_prop(new_child,
360626947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
36077c478bd9Sstevel@tonic-gate 				goto failedchild;
36087c478bd9Sstevel@tonic-gate 			}
360926947304SEvan Yan 		} else {
361026947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for "
361126947304SEvan Yan 			    "[0x0]=[0x0](32)\n", i);
361226947304SEvan Yan 			i += 4;
361326947304SEvan Yan 			continue;
36147c478bd9Sstevel@tonic-gate 		}
361570025d76Sjohnny 
361626947304SEvan Yan 		/*
361726947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
361826947304SEvan Yan 		 */
361926947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
362026947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
362126947304SEvan Yan 			    "[0x%x]=[0x%x] (64)\n",
362226947304SEvan Yan 			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362326947304SEvan Yan 			i += 8;
362426947304SEvan Yan 		} else {
362526947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for "
362626947304SEvan Yan 			    "[0x%x]=[0x%x](32)\n",
362726947304SEvan Yan 			    i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362826947304SEvan Yan 			i += 4;
362970025d76Sjohnny 		}
36307c478bd9Sstevel@tonic-gate 	}
36317c478bd9Sstevel@tonic-gate 
363226947304SEvan Yan 	/*
363326947304SEvan Yan 	 * Get the ROM size and create register for it
363426947304SEvan Yan 	 */
363526947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
363626947304SEvan Yan 
363726947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
363826947304SEvan Yan 	/*
363926947304SEvan Yan 	 * If its a zero length, don't do
364026947304SEvan Yan 	 * any programming.
364126947304SEvan Yan 	 */
364226947304SEvan Yan 
364326947304SEvan Yan 	if (request != 0) {
364426947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
364526947304SEvan Yan 		    PCI_CONF_ROM, request,
364626947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
364726947304SEvan Yan 		/*
364826947304SEvan Yan 		 * Add to the "reg" property
364926947304SEvan Yan 		 */
365026947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
365126947304SEvan Yan 		    != PCICFG_SUCCESS) {
365226947304SEvan Yan 			goto failedchild;
365326947304SEvan Yan 		}
365426947304SEvan Yan 	}
36557c478bd9Sstevel@tonic-gate 
36567c478bd9Sstevel@tonic-gate 	return (PCICFG_SUCCESS);
36577c478bd9Sstevel@tonic-gate 
36587c478bd9Sstevel@tonic-gate failedchild:
365926947304SEvan Yan 	return (PCICFG_FAILURE);
366026947304SEvan Yan }
366126947304SEvan Yan 
366226947304SEvan Yan /*
366326947304SEvan Yan  * Read the BARs and update properties. Used in virtual hotplug.
366426947304SEvan Yan  */
366526947304SEvan Yan static int
pcicfg_populate_props_from_bar(dev_info_t * new_child,ddi_acc_handle_t config_handle)366626947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child,
366726947304SEvan Yan     ddi_acc_handle_t config_handle)
366826947304SEvan Yan {
366926947304SEvan Yan 	uint32_t request, base, base_hi, size;
367026947304SEvan Yan 	int i;
367126947304SEvan Yan 
367226947304SEvan Yan 	i = PCI_CONF_BASE0;
367326947304SEvan Yan 
367426947304SEvan Yan 	while (i <= PCI_CONF_BASE5) {
367526947304SEvan Yan 		/*
367626947304SEvan Yan 		 * determine the size of the address space
367726947304SEvan Yan 		 */
367826947304SEvan Yan 		base = pci_config_get32(config_handle, i);
367926947304SEvan Yan 		pci_config_put32(config_handle, i, 0xffffffff);
368026947304SEvan Yan 		request = pci_config_get32(config_handle, i);
368126947304SEvan Yan 		pci_config_put32(config_handle, i, base);
368226947304SEvan Yan 
368326947304SEvan Yan 		/*
368426947304SEvan Yan 		 * If its a zero length, don't do any programming.
368526947304SEvan Yan 		 */
368626947304SEvan Yan 		if (request != 0) {
368726947304SEvan Yan 			/*
368826947304SEvan Yan 			 * Add to the "reg" property
368926947304SEvan Yan 			 */
369026947304SEvan Yan 			if (pcicfg_update_reg_prop(new_child,
369126947304SEvan Yan 			    request, i) != PCICFG_SUCCESS) {
369226947304SEvan Yan 				goto failedchild;
369326947304SEvan Yan 			}
369426947304SEvan Yan 
369526947304SEvan Yan 			if ((PCI_BASE_SPACE_IO & request) == 0 &&
369626947304SEvan Yan 			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
369726947304SEvan Yan 				base_hi = pci_config_get32(config_handle, i+4);
369826947304SEvan Yan 			} else {
369926947304SEvan Yan 				base_hi = 0;
370026947304SEvan Yan 			}
370126947304SEvan Yan 			/*
370226947304SEvan Yan 			 * Add to "assigned-addresses" property
370326947304SEvan Yan 			 */
370426947304SEvan Yan 			size = (~(PCI_BASE_M_ADDR_M & request))+1;
370526947304SEvan Yan 			if (pcicfg_update_assigned_prop_value(new_child,
370626947304SEvan Yan 			    size, base, base_hi, i) != PCICFG_SUCCESS) {
370726947304SEvan Yan 				goto failedchild;
370826947304SEvan Yan 			}
370926947304SEvan Yan 		} else {
371026947304SEvan Yan 			DEBUG1("BASE register [0x%x] asks for [0x0]=[0x0]"
371126947304SEvan Yan 			    "(32)\n", i);
371226947304SEvan Yan 			i += 4;
371326947304SEvan Yan 			continue;
371426947304SEvan Yan 		}
371526947304SEvan Yan 
371626947304SEvan Yan 		/*
371726947304SEvan Yan 		 * Increment by eight if it is 64 bit address space
371826947304SEvan Yan 		 */
371926947304SEvan Yan 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
372026947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
372126947304SEvan Yan 			    "(64)\n", i, request,
372226947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
372326947304SEvan Yan 			i += 8;
372426947304SEvan Yan 		} else {
372526947304SEvan Yan 			DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
372626947304SEvan Yan 			    "(32)\n", i, request,
372726947304SEvan Yan 			    (~(PCI_BASE_M_ADDR_M & request)) + 1);
372826947304SEvan Yan 			i += 4;
372926947304SEvan Yan 		}
373026947304SEvan Yan 	}
373126947304SEvan Yan 
37327c478bd9Sstevel@tonic-gate 	/*
373326947304SEvan Yan 	 * Get the ROM size and create register for it
37347c478bd9Sstevel@tonic-gate 	 */
373526947304SEvan Yan 	base = pci_config_get32(config_handle, PCI_CONF_ROM);
373626947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
373726947304SEvan Yan 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
373826947304SEvan Yan 	pci_config_put32(config_handle, PCI_CONF_ROM, base);
37397c478bd9Sstevel@tonic-gate 
374026947304SEvan Yan 	/*
374126947304SEvan Yan 	 * If its a zero length, don't do
374226947304SEvan Yan 	 * any programming.
374326947304SEvan Yan 	 */
374426947304SEvan Yan 	if (request != 0) {
374526947304SEvan Yan 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
374626947304SEvan Yan 		    PCI_CONF_ROM, request,
374726947304SEvan Yan 		    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
374826947304SEvan Yan 		/*
374926947304SEvan Yan 		 * Add to the "reg" property
375026947304SEvan Yan 		 */
375126947304SEvan Yan 		if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
375226947304SEvan Yan 		    != PCICFG_SUCCESS) {
375326947304SEvan Yan 			goto failedchild;
375426947304SEvan Yan 		}
375526947304SEvan Yan 		/*
375626947304SEvan Yan 		 * Add to "assigned-addresses" property
375726947304SEvan Yan 		 */
375826947304SEvan Yan 		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
375926947304SEvan Yan 		if (pcicfg_update_assigned_prop_value(new_child, size,
376026947304SEvan Yan 		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
376126947304SEvan Yan 			goto failedchild;
376226947304SEvan Yan 		}
376326947304SEvan Yan 	}
37647c478bd9Sstevel@tonic-gate 
376526947304SEvan Yan 	return (PCICFG_SUCCESS);
376626947304SEvan Yan 
376726947304SEvan Yan failedchild:
376826947304SEvan Yan 	return (PCICFG_FAILURE);
37697c478bd9Sstevel@tonic-gate }
37707c478bd9Sstevel@tonic-gate 
377170025d76Sjohnny 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)377270025d76Sjohnny pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
3773c0da6274SZhi-Jun Robin Fu     uint_t *highest_bus, boolean_t is_pcie)
377470025d76Sjohnny {
377570025d76Sjohnny 	uint64_t next_bus;
377670025d76Sjohnny 	uint_t new_bus, num_slots;
377770025d76Sjohnny 	ndi_ra_request_t req;
377870025d76Sjohnny 	int rval, i, j;
377970025d76Sjohnny 	uint64_t mem_answer, io_answer, mem_base, io_base, mem_alen, io_alen;
3780a6469d9bSprasad 	uint64_t pf_mem_answer, pf_mem_base, pf_mem_alen;
3781a6469d9bSprasad 	uint64_t mem_size, io_size, pf_mem_size;
3782a6469d9bSprasad 	uint64_t mem_end, pf_mem_end, io_end;
378370025d76Sjohnny 	uint64_t round_answer, round_len;
378400d0963fSdilpreet 	ppb_ranges_t range[PCICFG_RANGE_LEN];
378570025d76Sjohnny 	int bus_range[2];
378670025d76Sjohnny 	pcicfg_phdl_t phdl;
378770025d76Sjohnny 	uint64_t pcibus_base, pcibus_alen;
378870025d76Sjohnny 	uint64_t max_bus;
378970025d76Sjohnny 	uint8_t pcie_device_type = 0;
3790a6469d9bSprasad 	uint_t pf_mem_supported = 0;
379126947304SEvan Yan 	dev_info_t *new_device;
379226947304SEvan Yan 	int trans_device;
379326947304SEvan Yan 	int ari_mode = B_FALSE;
379426947304SEvan Yan 	int max_function = PCI_MAX_FUNCTIONS;
3795a6469d9bSprasad 
3796a6469d9bSprasad 	io_answer = io_base = io_alen = io_size = 0;
3797a6469d9bSprasad 	pf_mem_answer = pf_mem_base = pf_mem_size = pf_mem_alen = 0;
379870025d76Sjohnny 
379926947304SEvan Yan 	/*
380026947304SEvan Yan 	 * Set "device_type" to "pci", the actual type will be set later
380126947304SEvan Yan 	 * by pcicfg_set_busnode_props() below. This is needed as the
380226947304SEvan Yan 	 * pcicfg_ra_free() below would update "available" property based
380326947304SEvan Yan 	 * on "device_type".
380426947304SEvan Yan 	 *
380526947304SEvan Yan 	 * This code can be removed later after PCI configurator is changed
380626947304SEvan Yan 	 * to use PCIRM, which automatically update properties upon allocation
380726947304SEvan Yan 	 * and free, at that time we'll be able to remove the code inside
380826947304SEvan Yan 	 * ndi_ra_alloc/free() which currently updates "available" property
380926947304SEvan Yan 	 * for pci/pcie devices in pcie fabric.
381026947304SEvan Yan 	 */
381126947304SEvan Yan 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
381226947304SEvan Yan 	    "device_type", "pci") != DDI_SUCCESS) {
381326947304SEvan Yan 		DEBUG0("Failed to set \"device_type\" props\n");
381426947304SEvan Yan 		return (PCICFG_FAILURE);
381526947304SEvan Yan 	}
381626947304SEvan Yan 
3817a6469d9bSprasad 	/*
3818a6469d9bSprasad 	 * setup resource maps for the bridge node
3819a6469d9bSprasad 	 */
3820a6469d9bSprasad 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
382126947304SEvan Yan 	    == NDI_FAILURE) {
3822a6469d9bSprasad 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
3823a6469d9bSprasad 		rval = PCICFG_FAILURE;
3824a6469d9bSprasad 		goto cleanup;
3825a6469d9bSprasad 	}
3826a6469d9bSprasad 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
3827a6469d9bSprasad 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
3828a6469d9bSprasad 		rval = PCICFG_FAILURE;
3829a6469d9bSprasad 		goto cleanup;
3830a6469d9bSprasad 	}
3831a6469d9bSprasad 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
3832a6469d9bSprasad 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
3833a6469d9bSprasad 		rval = PCICFG_FAILURE;
3834a6469d9bSprasad 		goto cleanup;
3835a6469d9bSprasad 	}
3836a6469d9bSprasad 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
383726947304SEvan Yan 	    NDI_FAILURE) {
3838a6469d9bSprasad 		DEBUG0("Can not setup resource map -"
383926947304SEvan Yan 		    " NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
3840a6469d9bSprasad 		rval = PCICFG_FAILURE;
3841a6469d9bSprasad 		goto cleanup;
3842a6469d9bSprasad 	}
3843a6469d9bSprasad 
3844a6469d9bSprasad 	/*
3845a6469d9bSprasad 	 * Allocate bus range pool for the bridge.
3846a6469d9bSprasad 	 */
384770025d76Sjohnny 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
384870025d76Sjohnny 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
384970025d76Sjohnny 	req.ra_boundbase = 0;
385023c35297Sanish 	req.ra_boundlen = req.ra_len = (PCI_MAX_BUS_NUM -1);
385170025d76Sjohnny 	req.ra_align_mask = 0;  /* no alignment needed */
385270025d76Sjohnny 
385370025d76Sjohnny 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
385470025d76Sjohnny 	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
385570025d76Sjohnny 
385670025d76Sjohnny 	if (rval != NDI_SUCCESS) {
385770025d76Sjohnny 		if (rval == NDI_RA_PARTIAL_REQ) {
385870025d76Sjohnny 			/*EMPTY*/
385970025d76Sjohnny 			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
386070025d76Sjohnny 		} else {
386170025d76Sjohnny 			DEBUG0(
386270025d76Sjohnny 			    "Failed to allocate bus range for bridge\n");
38635af4ae46Sjveta 			rval = PCICFG_NORESRC;
3864a6469d9bSprasad 			goto cleanup;
386570025d76Sjohnny 		}
386670025d76Sjohnny 	}
386770025d76Sjohnny 
386870025d76Sjohnny 	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
386926947304SEvan Yan 	    pcibus_base, pcibus_alen);
387070025d76Sjohnny 
387170025d76Sjohnny 	/*
387270025d76Sjohnny 	 * Put available bus range into the pool.
387370025d76Sjohnny 	 * Take the first one for this bridge to use and don't give
387470025d76Sjohnny 	 * to child.
387570025d76Sjohnny 	 */
387670025d76Sjohnny 	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
387726947304SEvan Yan 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
387870025d76Sjohnny 
387970025d76Sjohnny 	next_bus = pcibus_base;
388070025d76Sjohnny 	max_bus = pcibus_base + pcibus_alen - 1;
388170025d76Sjohnny 
388270025d76Sjohnny 	new_bus = next_bus;
388370025d76Sjohnny 
388470025d76Sjohnny 	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
388570025d76Sjohnny 
388670025d76Sjohnny 	/* Keep track of highest bus for subordinate bus programming */
388770025d76Sjohnny 	*highest_bus = new_bus;
388870025d76Sjohnny 
388970025d76Sjohnny 	/*
3890a6469d9bSprasad 	 * Allocate (non-prefetchable) Memory Space for Bridge
389170025d76Sjohnny 	 */
389270025d76Sjohnny 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
389370025d76Sjohnny 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
389470025d76Sjohnny 	req.ra_boundbase = 0;
389570025d76Sjohnny 	/*
389670025d76Sjohnny 	 * limit the boundlen,len to a 32b quantity. It should be Ok to
389770025d76Sjohnny 	 * lose alignment-based-size of resource due to this.
389870025d76Sjohnny 	 */
389970025d76Sjohnny 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
390070025d76Sjohnny 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
390170025d76Sjohnny 	req.ra_align_mask =
390270025d76Sjohnny 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
390370025d76Sjohnny 
390470025d76Sjohnny 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
390570025d76Sjohnny 	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
390670025d76Sjohnny 
390770025d76Sjohnny 	if (rval != NDI_SUCCESS) {
390870025d76Sjohnny 		if (rval == NDI_RA_PARTIAL_REQ) {
390970025d76Sjohnny 			/*EMPTY*/
391070025d76Sjohnny 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
391170025d76Sjohnny 		} else {
391270025d76Sjohnny 			DEBUG0(
391370025d76Sjohnny 			    "Failed to allocate memory for bridge\n");
39145af4ae46Sjveta 			rval = PCICFG_NORESRC;
3915a6469d9bSprasad 			goto cleanup;
391670025d76Sjohnny 		}
391770025d76Sjohnny 	}
391870025d76Sjohnny 
391970025d76Sjohnny 	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
392070025d76Sjohnny 	    PCICFG_HIADDR(mem_answer),
392170025d76Sjohnny 	    PCICFG_LOADDR(mem_answer),
392270025d76Sjohnny 	    mem_alen);
392370025d76Sjohnny 
392470025d76Sjohnny 	/*
392570025d76Sjohnny 	 * Put available memory into the pool.
392670025d76Sjohnny 	 */
392770025d76Sjohnny 	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
392870025d76Sjohnny 	    NDI_RA_PASS);
392970025d76Sjohnny 
393070025d76Sjohnny 	mem_base = mem_answer;
393170025d76Sjohnny 
393270025d76Sjohnny 	/*
393370025d76Sjohnny 	 * Allocate I/O Space for Bridge
393470025d76Sjohnny 	 */
393570025d76Sjohnny 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
393670025d76Sjohnny 	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
393770025d76Sjohnny 	req.ra_boundbase = 0;
393870025d76Sjohnny 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
393970025d76Sjohnny 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
394070025d76Sjohnny 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
394170025d76Sjohnny 
394270025d76Sjohnny 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
394370025d76Sjohnny 	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
394470025d76Sjohnny 
394570025d76Sjohnny 	if (rval != NDI_SUCCESS) {
394670025d76Sjohnny 		if (rval == NDI_RA_PARTIAL_REQ) {
394770025d76Sjohnny 			/*EMPTY*/
394870025d76Sjohnny 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
394970025d76Sjohnny 		} else {
395070025d76Sjohnny 			DEBUG0("Failed to allocate io space for bridge\n");
3951a6469d9bSprasad 			/* i/o space is an optional requirement so continue */
395270025d76Sjohnny 		}
395370025d76Sjohnny 	}
395470025d76Sjohnny 
395570025d76Sjohnny 	DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
395670025d76Sjohnny 	    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), io_alen);
395770025d76Sjohnny 
395870025d76Sjohnny 	/*
395970025d76Sjohnny 	 * Put available I/O into the pool.
396070025d76Sjohnny 	 */
396170025d76Sjohnny 	(void) ndi_ra_free(new_child, io_answer, io_alen, NDI_RA_TYPE_IO,
396270025d76Sjohnny 	    NDI_RA_PASS);
396370025d76Sjohnny 
396470025d76Sjohnny 	io_base = io_answer;
396570025d76Sjohnny 
3966a6469d9bSprasad 	/*
3967a6469d9bSprasad 	 * Check if the bridge supports Prefetchable memory range.
3968a6469d9bSprasad 	 * If it does, then we setup PF memory range for the bridge.
3969a6469d9bSprasad 	 * Otherwise, we skip the step of setting up PF memory
3970a6469d9bSprasad 	 * range for it. This could cause config operation to
3971a6469d9bSprasad 	 * fail if any devices under the bridge need PF memory.
3972a6469d9bSprasad 	 */
3973a6469d9bSprasad 	/* write a non zero value to the PF BASE register */
3974a6469d9bSprasad 	pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
3975a6469d9bSprasad 	/* if the read returns zero then PF range is not supported */
3976a6469d9bSprasad 	if (pci_config_get16(h, PCI_BCNF_PF_BASE_LOW) == 0) {
3977a6469d9bSprasad 		/* bridge doesn't support PF memory range */
3978a6469d9bSprasad 		goto pf_setup_end;
3979a6469d9bSprasad 	} else {
3980a6469d9bSprasad 		pf_mem_supported = 1;
3981a6469d9bSprasad 		/* reset the PF BASE register */
3982a6469d9bSprasad 		pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0);
3983a6469d9bSprasad 	}
398470025d76Sjohnny 
398570025d76Sjohnny 	/*
3986a6469d9bSprasad 	 * Bridge supports PF mem range; Allocate PF Memory Space for it.
3987a6469d9bSprasad 	 *
3988a6469d9bSprasad 	 * Note: Both non-prefetchable and prefetchable memory space
3989a6469d9bSprasad 	 * allocations are made within 32bit space. Currently, BIOSs
3990a6469d9bSprasad 	 * allocate device memory for PCI devices within the 32bit space
3991a6469d9bSprasad 	 * so this will not be a problem.
399270025d76Sjohnny 	 */
3993a6469d9bSprasad 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
3994a6469d9bSprasad 	req.ra_flags = NDI_RA_ALLOC_PARTIAL_OK | NDI_RA_ALLOC_BOUNDED;
3995a6469d9bSprasad 	req.ra_boundbase = 0;
3996a6469d9bSprasad 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
3997a6469d9bSprasad 	req.ra_align_mask =
3998a6469d9bSprasad 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
399970025d76Sjohnny 
4000a6469d9bSprasad 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
4001a6469d9bSprasad 	    &pf_mem_answer, &pf_mem_alen,  NDI_RA_TYPE_PCI_PREFETCH_MEM,
4002a6469d9bSprasad 	    NDI_RA_PASS);
400370025d76Sjohnny 
4004a6469d9bSprasad 	if (rval != NDI_SUCCESS) {
4005a6469d9bSprasad 		if (rval == NDI_RA_PARTIAL_REQ) {
4006a6469d9bSprasad 			/*EMPTY*/
4007a6469d9bSprasad 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
4008a6469d9bSprasad 		} else {
4009a6469d9bSprasad 			DEBUG0(
4010a6469d9bSprasad 			    "Failed to allocate PF memory for bridge\n");
4011a6469d9bSprasad 			/* PF mem is an optional requirement so continue */
4012a6469d9bSprasad 		}
4013a6469d9bSprasad 	}
4014a6469d9bSprasad 
4015a6469d9bSprasad 	DEBUG3("Bridge PF Memory Allocated [0x%x.%x] len [0x%x]\n",
4016a6469d9bSprasad 	    PCICFG_HIADDR(pf_mem_answer),
4017a6469d9bSprasad 	    PCICFG_LOADDR(pf_mem_answer),
4018a6469d9bSprasad 	    pf_mem_alen);
4019a6469d9bSprasad 
4020a6469d9bSprasad 	/*
4021a6469d9bSprasad 	 * Put available PF memory into the pool.
4022a6469d9bSprasad 	 */
4023a6469d9bSprasad 	(void) ndi_ra_free(new_child, pf_mem_answer, pf_mem_alen,
4024a6469d9bSprasad 	    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
4025a6469d9bSprasad 
4026a6469d9bSprasad 	pf_mem_base = pf_mem_answer;
4027a6469d9bSprasad 
4028a6469d9bSprasad 	/*
4029a6469d9bSprasad 	 * Program the PF memory base register with the
4030a6469d9bSprasad 	 * start of the memory range
4031a6469d9bSprasad 	 */
4032a6469d9bSprasad 	pci_config_put16(h, PCI_BCNF_PF_BASE_LOW,
4033a6469d9bSprasad 	    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_answer)));
4034a6469d9bSprasad 	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH,
4035a6469d9bSprasad 	    PCICFG_HIADDR(pf_mem_answer));
4036a6469d9bSprasad 
4037a6469d9bSprasad 	/*
4038a6469d9bSprasad 	 * Program the PF memory limit register with the
4039a6469d9bSprasad 	 * end of the memory range.
4040a6469d9bSprasad 	 */
4041a6469d9bSprasad 	pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
4042a6469d9bSprasad 	    PCICFG_HIWORD(PCICFG_LOADDR(
4043a6469d9bSprasad 	    PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4044a6469d9bSprasad 	    PCICFG_MEMGRAN) - 1)));
4045a6469d9bSprasad 	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
4046a6469d9bSprasad 	    PCICFG_HIADDR(PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4047a6469d9bSprasad 	    PCICFG_MEMGRAN) - 1));
4048a6469d9bSprasad 
4049a6469d9bSprasad 	/*
4050a6469d9bSprasad 	 * Allocate the chunk of PF memory (if any) not programmed into the
4051a6469d9bSprasad 	 * bridge because of the round down.
4052a6469d9bSprasad 	 */
4053a6469d9bSprasad 	if (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen), PCICFG_MEMGRAN)
4054a6469d9bSprasad 	    != (pf_mem_answer + pf_mem_alen)) {
4055a6469d9bSprasad 		DEBUG0("Need to allocate Memory round off chunk\n");
4056a6469d9bSprasad 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
4057a6469d9bSprasad 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
4058a6469d9bSprasad 		req.ra_addr = PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4059a6469d9bSprasad 		    PCICFG_MEMGRAN);
4060a6469d9bSprasad 		req.ra_len =  (pf_mem_answer + pf_mem_alen) -
4061a6469d9bSprasad 		    (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4062a6469d9bSprasad 		    PCICFG_MEMGRAN));
4063a6469d9bSprasad 
4064a6469d9bSprasad 		(void) ndi_ra_alloc(new_child, &req,
4065a6469d9bSprasad 		    &round_answer, &round_len,  NDI_RA_TYPE_PCI_PREFETCH_MEM,
4066a6469d9bSprasad 		    NDI_RA_PASS);
4067a6469d9bSprasad 	}
4068a6469d9bSprasad 
4069a6469d9bSprasad pf_setup_end:
407070025d76Sjohnny 
407170025d76Sjohnny 	/*
407270025d76Sjohnny 	 * Program the memory base register with the
407370025d76Sjohnny 	 * start of the memory range
407470025d76Sjohnny 	 */
407570025d76Sjohnny 	pci_config_put16(h, PCI_BCNF_MEM_BASE,
407670025d76Sjohnny 	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
407770025d76Sjohnny 
407870025d76Sjohnny 	/*
407970025d76Sjohnny 	 * Program the memory limit register with the
408070025d76Sjohnny 	 * end of the memory range.
408170025d76Sjohnny 	 */
408270025d76Sjohnny 
408370025d76Sjohnny 	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
408470025d76Sjohnny 	    PCICFG_HIWORD(PCICFG_LOADDR(
408570025d76Sjohnny 	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
408670025d76Sjohnny 
408770025d76Sjohnny 	/*
408870025d76Sjohnny 	 * Allocate the chunk of memory (if any) not programmed into the
408970025d76Sjohnny 	 * bridge because of the round down.
409070025d76Sjohnny 	 */
409170025d76Sjohnny 	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
409270025d76Sjohnny 	    != (mem_answer + mem_alen)) {
409370025d76Sjohnny 		DEBUG0("Need to allocate Memory round off chunk\n");
409470025d76Sjohnny 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
409570025d76Sjohnny 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
409670025d76Sjohnny 		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
409770025d76Sjohnny 		    PCICFG_MEMGRAN);
409870025d76Sjohnny 		req.ra_len =  (mem_answer + mem_alen) -
409970025d76Sjohnny 		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
410070025d76Sjohnny 		    PCICFG_MEMGRAN));
410170025d76Sjohnny 
410270025d76Sjohnny 		(void) ndi_ra_alloc(new_child, &req,
410370025d76Sjohnny 		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
410470025d76Sjohnny 	}
410570025d76Sjohnny 
410670025d76Sjohnny 	/*
410770025d76Sjohnny 	 * Program the I/O Space Base
410870025d76Sjohnny 	 */
410970025d76Sjohnny 	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
411070025d76Sjohnny 	    PCICFG_HIBYTE(PCICFG_LOWORD(
411170025d76Sjohnny 	    PCICFG_LOADDR(io_answer))));
411270025d76Sjohnny 
411370025d76Sjohnny 	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
411470025d76Sjohnny 	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
411570025d76Sjohnny 
411670025d76Sjohnny 	/*
411770025d76Sjohnny 	 * Program the I/O Space Limit
411870025d76Sjohnny 	 */
411970025d76Sjohnny 	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
412070025d76Sjohnny 	    PCICFG_HIBYTE(PCICFG_LOWORD(
412170025d76Sjohnny 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
412270025d76Sjohnny 	    PCICFG_IOGRAN)))) - 1);
412370025d76Sjohnny 
412470025d76Sjohnny 	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
412570025d76Sjohnny 	    PCICFG_HIWORD(PCICFG_LOADDR(
412670025d76Sjohnny 	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
412770025d76Sjohnny 	    - 1);
412870025d76Sjohnny 
412970025d76Sjohnny 	/*
413070025d76Sjohnny 	 * Allocate the chunk of I/O (if any) not programmed into the
413170025d76Sjohnny 	 * bridge because of the round down.
413270025d76Sjohnny 	 */
413370025d76Sjohnny 	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
413470025d76Sjohnny 	    != (io_answer + io_alen)) {
413570025d76Sjohnny 		DEBUG0("Need to allocate I/O round off chunk\n");
413670025d76Sjohnny 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
413770025d76Sjohnny 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
413870025d76Sjohnny 		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
413970025d76Sjohnny 		    PCICFG_IOGRAN);
414070025d76Sjohnny 		req.ra_len =  (io_answer + io_alen) -
414170025d76Sjohnny 		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
414270025d76Sjohnny 		    PCICFG_IOGRAN));
414370025d76Sjohnny 
414470025d76Sjohnny 		(void) ndi_ra_alloc(new_child, &req,
414570025d76Sjohnny 		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
414670025d76Sjohnny 	}
414770025d76Sjohnny 
4148a6469d9bSprasad 	(void) pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
4149a6469d9bSprasad 
41503f9ec228SZhi-Jun Robin Fu 	/*
41513f9ec228SZhi-Jun Robin Fu 	 * Setup "ranges" and "bus-range" properties before onlining
41523f9ec228SZhi-Jun Robin Fu 	 * the bridge.
41533f9ec228SZhi-Jun Robin Fu 	 */
41543f9ec228SZhi-Jun Robin Fu 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
41553f9ec228SZhi-Jun Robin Fu 
41563f9ec228SZhi-Jun Robin Fu 	range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
41573f9ec228SZhi-Jun Robin Fu 	    PCI_ADDR_IO);
41583f9ec228SZhi-Jun Robin Fu 	range[0].child_low = range[0].parent_low = io_base;
41593f9ec228SZhi-Jun Robin Fu 	range[1].child_high = range[1].parent_high |=
41603f9ec228SZhi-Jun Robin Fu 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
41613f9ec228SZhi-Jun Robin Fu 	range[1].child_low = range[1].parent_low = mem_base;
41623f9ec228SZhi-Jun Robin Fu 	range[2].child_high = range[2].parent_high |=
41633f9ec228SZhi-Jun Robin Fu 	    (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
41643f9ec228SZhi-Jun Robin Fu 	range[2].child_low = range[2].parent_low = pf_mem_base;
41653f9ec228SZhi-Jun Robin Fu 
41663f9ec228SZhi-Jun Robin Fu 	range[0].size_low = io_alen;
41673f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[0]);
41683f9ec228SZhi-Jun Robin Fu 	range[1].size_low = mem_alen;
41693f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[1]);
41703f9ec228SZhi-Jun Robin Fu 	range[2].size_low = pf_mem_alen;
41713f9ec228SZhi-Jun Robin Fu 	(void) pcicfg_update_ranges_prop(new_child, &range[2]);
41723f9ec228SZhi-Jun Robin Fu 
41733f9ec228SZhi-Jun Robin Fu 	bus_range[0] = new_bus;
41743f9ec228SZhi-Jun Robin Fu 	bus_range[1] = max_bus;
41753f9ec228SZhi-Jun Robin Fu 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
41763f9ec228SZhi-Jun Robin Fu 	    "bus-range", bus_range, 2);
41773f9ec228SZhi-Jun Robin Fu 
417870025d76Sjohnny 	/*
4179a6469d9bSprasad 	 * Reset the secondary bus
418070025d76Sjohnny 	 */
4181a6469d9bSprasad 	pci_config_put16(h, PCI_BCNF_BCNTRL,
4182a6469d9bSprasad 	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
4183a6469d9bSprasad 
4184a6469d9bSprasad 	drv_usecwait(100);
4185a6469d9bSprasad 
4186a6469d9bSprasad 	pci_config_put16(h, PCI_BCNF_BCNTRL,
4187a6469d9bSprasad 	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
418870025d76Sjohnny 
418970025d76Sjohnny 	/*
4190a6469d9bSprasad 	 * Clear status bits
419170025d76Sjohnny 	 */
4192a6469d9bSprasad 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
419370025d76Sjohnny 
419470025d76Sjohnny 	/*
419570025d76Sjohnny 	 * Needs to be set to this value
419670025d76Sjohnny 	 */
419770025d76Sjohnny 	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
419870025d76Sjohnny 
419970025d76Sjohnny 	/* check our device_type as defined by Open Firmware */
420070025d76Sjohnny 	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
420170025d76Sjohnny 		pcie_device_type = 1;
420270025d76Sjohnny 
420370025d76Sjohnny 	/*
420470025d76Sjohnny 	 * Set bus properties
420570025d76Sjohnny 	 */
420670025d76Sjohnny 	if (pcicfg_set_busnode_props(new_child, pcie_device_type)
420726947304SEvan Yan 	    != PCICFG_SUCCESS) {
420870025d76Sjohnny 		DEBUG0("Failed to set busnode props\n");
4209a6469d9bSprasad 		rval = PCICFG_FAILURE;
4210a6469d9bSprasad 		goto cleanup;
421170025d76Sjohnny 	}
421270025d76Sjohnny 
421370025d76Sjohnny 	(void) pcicfg_device_on(h);
421470025d76Sjohnny 
4215c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4216c1374a13SSurya Prakki 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
421770025d76Sjohnny 	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
421870025d76Sjohnny 	    != NDI_SUCCESS) {
421970025d76Sjohnny 		DEBUG0("Unable to online bridge\n");
4220a6469d9bSprasad 		rval = PCICFG_FAILURE;
4221a6469d9bSprasad 		goto cleanup;
422270025d76Sjohnny 	}
422370025d76Sjohnny 
422470025d76Sjohnny 	DEBUG0("Bridge is ONLINE\n");
422570025d76Sjohnny 
422670025d76Sjohnny 	/*
422770025d76Sjohnny 	 * After a Reset, we need to wait 2^25 clock cycles before the
422870025d76Sjohnny 	 * first Configuration access.  The worst case is 33MHz, which
422970025d76Sjohnny 	 * is a 1 second wait.
423070025d76Sjohnny 	 */
423170025d76Sjohnny 	drv_usecwait(pcicfg_sec_reset_delay);
423270025d76Sjohnny 
423370025d76Sjohnny 	/*
423470025d76Sjohnny 	 * Probe all children devices
423570025d76Sjohnny 	 */
423670025d76Sjohnny 	DEBUG0("Bridge Programming Complete - probe children\n");
42373fe80ca4SDan Cross 	ndi_devi_enter(new_child);
423826947304SEvan Yan 	for (i = 0; ((i < PCI_MAX_DEVICES) && (ari_mode == B_FALSE));
423926947304SEvan Yan 	    i++) {
424026947304SEvan Yan 		for (j = 0; j < max_function; ) {
424126947304SEvan Yan 			if (ari_mode)
424226947304SEvan Yan 				trans_device = j >> 3;
424326947304SEvan Yan 			else
424426947304SEvan Yan 				trans_device = i;
424526947304SEvan Yan 
424670025d76Sjohnny 			if ((rval = pcicfg_probe_children(new_child,
4247c0da6274SZhi-Jun Robin Fu 			    new_bus, trans_device, j & 7, highest_bus,
4248c0da6274SZhi-Jun Robin Fu 			    0, is_pcie)) != PCICFG_SUCCESS) {
424970025d76Sjohnny 				if (rval == PCICFG_NODEVICE) {
425070025d76Sjohnny 					DEBUG3("No Device at bus [0x%x]"
425126947304SEvan Yan 					    "device [0x%x] "
425226947304SEvan Yan 					    "func [0x%x]\n", new_bus,
425326947304SEvan Yan 					    trans_device, j & 7);
425426947304SEvan Yan 
425570025d76Sjohnny 					if (j)
425626947304SEvan Yan 						goto next;
425770025d76Sjohnny 				} else
425870025d76Sjohnny 					/*EMPTY*/
425970025d76Sjohnny 					DEBUG3("Failed to configure bus "
426026947304SEvan Yan 					    "[0x%x] device [0x%x] "
426126947304SEvan Yan 					    "func [0x%x]\n", new_bus,
426226947304SEvan Yan 					    trans_device, j & 7);
426370025d76Sjohnny 				break;
426470025d76Sjohnny 			}
426526947304SEvan Yan next:
426626947304SEvan Yan 			new_device = pcicfg_devi_find(new_child, trans_device,
426726947304SEvan Yan 			    (j & 7));
426826947304SEvan Yan 
426926947304SEvan Yan 			/*
427026947304SEvan Yan 			 * Determine if ARI Forwarding should be enabled.
427126947304SEvan Yan 			 */
427226947304SEvan Yan 			if (j == 0) {
427326947304SEvan Yan 				if (new_device == NULL)
427426947304SEvan Yan 					break;
427526947304SEvan Yan 
427626947304SEvan Yan 				if ((pcie_ari_supported(new_child) ==
427726947304SEvan Yan 				    PCIE_ARI_FORW_SUPPORTED) &&
427826947304SEvan Yan 				    (pcie_ari_device(new_device) ==
427926947304SEvan Yan 				    PCIE_ARI_DEVICE)) {
428026947304SEvan Yan 					if (pcie_ari_enable(new_child) ==
428126947304SEvan Yan 					    DDI_SUCCESS) {
428226947304SEvan Yan 						(void) ddi_prop_create(
428326947304SEvan Yan 						    DDI_DEV_T_NONE,
428426947304SEvan Yan 						    new_child,
428526947304SEvan Yan 						    DDI_PROP_CANSLEEP,
428626947304SEvan Yan 						    "ari-enabled", NULL, 0);
428726947304SEvan Yan 						ari_mode = B_TRUE;
428826947304SEvan Yan 						max_function =
428926947304SEvan Yan 						    PCICFG_MAX_ARI_FUNCTION;
429026947304SEvan Yan 					}
429126947304SEvan Yan 				}
429226947304SEvan Yan 			}
429326947304SEvan Yan 			if (ari_mode == B_TRUE) {
429426947304SEvan Yan 				int next_function;
429526947304SEvan Yan 
429626947304SEvan Yan 				if (new_device == NULL)
429726947304SEvan Yan 					break;
429826947304SEvan Yan 
429926947304SEvan Yan 				if (pcie_ari_get_next_function(new_device,
430026947304SEvan Yan 				    &next_function) != DDI_SUCCESS)
430126947304SEvan Yan 					break;
430226947304SEvan Yan 
430326947304SEvan Yan 				j = next_function;
430426947304SEvan Yan 
430526947304SEvan Yan 				if (next_function == 0)
430626947304SEvan Yan 					break;
430726947304SEvan Yan 			} else
430826947304SEvan Yan 				j++;
430926947304SEvan Yan 
431070025d76Sjohnny 		}
431170025d76Sjohnny 		/* if any function fails to be configured, no need to proceed */
431270025d76Sjohnny 		if (rval != PCICFG_NODEVICE)
431370025d76Sjohnny 			break;
431470025d76Sjohnny 	}
43153fe80ca4SDan Cross 	ndi_devi_exit(new_child);
431670025d76Sjohnny 
431770025d76Sjohnny 	/*
431870025d76Sjohnny 	 * Offline the bridge to allow reprogramming of resources.
431926947304SEvan Yan 	 *
432026947304SEvan Yan 	 * This should always succeed since nobody else has started to
432126947304SEvan Yan 	 * use it yet, failing to detach the driver would indicate a bug.
432226947304SEvan Yan 	 * Also in that case it's better just panic than allowing the
432326947304SEvan Yan 	 * configurator to proceed with BAR reprogramming without bridge
432426947304SEvan Yan 	 * driver detached.
432570025d76Sjohnny 	 */
432626947304SEvan Yan 	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
432726947304SEvan Yan 	    == NDI_SUCCESS);
4328c0da6274SZhi-Jun Robin Fu 	if (is_pcie)
4329c0da6274SZhi-Jun Robin Fu 		pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
433070025d76Sjohnny 
433170025d76Sjohnny 	phdl.dip = new_child;
433270025d76Sjohnny 	phdl.memory_base = mem_answer;
433370025d76Sjohnny 	phdl.io_base = io_answer;
4334a6469d9bSprasad 	phdl.pf_memory_base = pf_mem_answer;
433570025d76Sjohnny 	phdl.error = PCICFG_SUCCESS;	/* in case of empty child tree */
433670025d76Sjohnny 
43373fe80ca4SDan Cross 	ndi_devi_enter(ddi_get_parent(new_child));
433870025d76Sjohnny 	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
43393fe80ca4SDan Cross 	ndi_devi_exit(ddi_get_parent(new_child));
434070025d76Sjohnny 
434170025d76Sjohnny 	num_slots = pcicfg_get_nslots(new_child, h);
434270025d76Sjohnny 	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
434370025d76Sjohnny 	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
4344a6469d9bSprasad 	pf_mem_end = PCICFG_ROUND_UP(phdl.pf_memory_base, PCICFG_MEMGRAN);
434570025d76Sjohnny 
434626947304SEvan Yan 	DEBUG4("Start of Unallocated Bridge(%d slots) Resources Mem=0x%lx "
434726947304SEvan Yan 	    "I/O=0x%lx PF_mem=%x%lx\n", num_slots, mem_end, io_end, pf_mem_end);
434870025d76Sjohnny 
434926947304SEvan Yan 	/*
435026947304SEvan Yan 	 * Before probing the children we've allocated maximum MEM/IO
435126947304SEvan Yan 	 * resources from parent, and updated "available" property
435226947304SEvan Yan 	 * accordingly. Later we'll be giving up unused resources to
435326947304SEvan Yan 	 * the parent, thus we need to destroy "available" property
435426947304SEvan Yan 	 * here otherwise it will be out-of-sync with the actual free
435526947304SEvan Yan 	 * resources this bridge has. This property will be rebuilt below
435626947304SEvan Yan 	 * with the actual free resources reserved for hotplug slots
435726947304SEvan Yan 	 * (if any).
435826947304SEvan Yan 	 */
435926947304SEvan Yan 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
436070025d76Sjohnny 	/*
436170025d76Sjohnny 	 * if the bridge a slots, then preallocate. If not, assume static
436270025d76Sjohnny 	 * configuration. Also check for preallocation limits and spit
436370025d76Sjohnny 	 * warning messages appropriately (perhaps some can be in debug mode).
436470025d76Sjohnny 	 */
436570025d76Sjohnny 	if (num_slots) {
436626947304SEvan Yan 		uint64_t mem_reqd = mem_answer +
436726947304SEvan Yan 		    (num_slots * pcicfg_slot_memsize);
436826947304SEvan Yan 		uint64_t io_reqd = io_answer +
436926947304SEvan Yan 		    (num_slots * pcicfg_slot_iosize);
437026947304SEvan Yan 		uint64_t pf_mem_reqd = pf_mem_answer +
437126947304SEvan Yan 		    (num_slots * pcicfg_slot_pf_memsize);
437226947304SEvan Yan 		uint8_t highest_bus_reqd = new_bus +
437326947304SEvan Yan 		    (num_slots * pcicfg_slot_busnums);
4374949b8557Sarutz #ifdef DEBUG
437570025d76Sjohnny 		if (mem_end > mem_reqd)
4376949b8557Sarutz 			DEBUG3("Memory space consumed by bridge more "
437770025d76Sjohnny 			    "than planned for %d slot(s)(%" PRIx64 ",%"
437870025d76Sjohnny 			    PRIx64 ")", num_slots, mem_answer, mem_end);
437970025d76Sjohnny 		if (io_end > io_reqd)
4380949b8557Sarutz 			DEBUG3("IO space consumed by bridge more than"
438170025d76Sjohnny 			    " planned for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
438270025d76Sjohnny 			    num_slots, io_answer, io_end);
4383a6469d9bSprasad 		if (pf_mem_end > pf_mem_reqd)
4384949b8557Sarutz 			DEBUG3("PF Memory space consumed by bridge"
4385a6469d9bSprasad 			    " more than planned for %d slot(s)(%" PRIx64 ",%"
4386a6469d9bSprasad 			    PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
438770025d76Sjohnny 		if (*highest_bus > highest_bus_reqd)
4388949b8557Sarutz 			DEBUG3("Buses consumed by bridge more "
438970025d76Sjohnny 			    "than planned for %d slot(s)(%x, %x)",
439070025d76Sjohnny 			    num_slots, new_bus, *highest_bus);
439170025d76Sjohnny 
439270025d76Sjohnny 		if (mem_reqd > (mem_answer + mem_alen))
4393949b8557Sarutz 			DEBUG3("Memory space required by bridge more "
439470025d76Sjohnny 			    "than available for %d slot(s)(%" PRIx64 ",%"
439570025d76Sjohnny 			    PRIx64 ")", num_slots, mem_answer, mem_end);
439670025d76Sjohnny 		if (io_reqd > (io_answer + io_alen))
4397949b8557Sarutz 			DEBUG3("IO space required by bridge more than"
439870025d76Sjohnny 			    "available for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
439970025d76Sjohnny 			    num_slots, io_answer, io_end);
4400a6469d9bSprasad 		if (pf_mem_reqd > (pf_mem_answer + pf_mem_alen))
4401949b8557Sarutz 			DEBUG3("PF Memory space required by bridge"
4402a6469d9bSprasad 			    " more than available for %d slot(s)(%" PRIx64 ",%"
4403a6469d9bSprasad 			    PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
440470025d76Sjohnny 		if (highest_bus_reqd > max_bus)
4405949b8557Sarutz 			DEBUG3("Bus numbers required by bridge more "
440670025d76Sjohnny 			    "than available for %d slot(s)(%x, %x)",
440770025d76Sjohnny 			    num_slots, new_bus, *highest_bus);
4408949b8557Sarutz #endif
440970025d76Sjohnny 		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
441026947304SEvan Yan 		    mem_end);
441170025d76Sjohnny 		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
4412a6469d9bSprasad 		pf_mem_end = MAX((MIN(pf_mem_reqd, (pf_mem_answer +
441326947304SEvan Yan 		    pf_mem_alen))), pf_mem_end);
441470025d76Sjohnny 		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
441526947304SEvan Yan 		    *highest_bus);
4416a6469d9bSprasad 		DEBUG4("mem_end %lx, io_end %lx, pf_mem_end %lx"
441726947304SEvan Yan 		    " highest_bus %x\n", mem_end, io_end, pf_mem_end,
441826947304SEvan Yan 		    *highest_bus);
441970025d76Sjohnny 	}
442070025d76Sjohnny 
442170025d76Sjohnny 	/*
442270025d76Sjohnny 	 * Give back unused memory space to parent.
442370025d76Sjohnny 	 */
442426947304SEvan Yan 	(void) ndi_ra_free(ddi_get_parent(new_child), mem_end,
442526947304SEvan Yan 	    (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, NDI_RA_PASS);
442670025d76Sjohnny 
442770025d76Sjohnny 	if (mem_end == mem_answer) {
442870025d76Sjohnny 		DEBUG0("No memory resources used\n");
442970025d76Sjohnny 		/*
443070025d76Sjohnny 		 * To prevent the bridge from forwarding any Memory
443170025d76Sjohnny 		 * transactions, the Memory Limit will be programmed
443270025d76Sjohnny 		 * with a smaller value than the Memory Base.
443370025d76Sjohnny 		 */
443470025d76Sjohnny 		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
443570025d76Sjohnny 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
443670025d76Sjohnny 
443770025d76Sjohnny 		mem_size = 0;
443870025d76Sjohnny 	} else {
443970025d76Sjohnny 		/*
444070025d76Sjohnny 		 * Reprogram the end of the memory.
444170025d76Sjohnny 		 */
444270025d76Sjohnny 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
444370025d76Sjohnny 		    PCICFG_HIWORD(mem_end) - 1);
444470025d76Sjohnny 		mem_size = mem_end - mem_base;
444570025d76Sjohnny 	}
444670025d76Sjohnny 
444770025d76Sjohnny 	/*
444870025d76Sjohnny 	 * Give back unused io space to parent.
444970025d76Sjohnny 	 */
445070025d76Sjohnny 	(void) ndi_ra_free(ddi_get_parent(new_child),
445170025d76Sjohnny 	    io_end, (io_answer + io_alen) - io_end,
445270025d76Sjohnny 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
445370025d76Sjohnny 
445470025d76Sjohnny 	if (io_end == io_answer) {
445570025d76Sjohnny 		DEBUG0("No IO Space resources used\n");
445670025d76Sjohnny 
445770025d76Sjohnny 		/*
445870025d76Sjohnny 		 * To prevent the bridge from forwarding any I/O
445970025d76Sjohnny 		 * transactions, the I/O Limit will be programmed
446070025d76Sjohnny 		 * with a smaller value than the I/O Base.
446170025d76Sjohnny 		 */
446270025d76Sjohnny 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
446370025d76Sjohnny 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
446470025d76Sjohnny 		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
446570025d76Sjohnny 		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
446670025d76Sjohnny 
446770025d76Sjohnny 		io_size = 0;
446870025d76Sjohnny 	} else {
446970025d76Sjohnny 		/*
447070025d76Sjohnny 		 * Reprogram the end of the io space.
447170025d76Sjohnny 		 */
447270025d76Sjohnny 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
447370025d76Sjohnny 		    PCICFG_HIBYTE(PCICFG_LOWORD(
447470025d76Sjohnny 		    PCICFG_LOADDR(io_end) - 1)));
447570025d76Sjohnny 
447670025d76Sjohnny 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
447770025d76Sjohnny 		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
447870025d76Sjohnny 
447970025d76Sjohnny 		io_size = io_end - io_base;
448070025d76Sjohnny 	}
448170025d76Sjohnny 
4482a6469d9bSprasad 	/*
4483a6469d9bSprasad 	 * Give back unused PF memory space to parent.
4484a6469d9bSprasad 	 */
4485a6469d9bSprasad 	if (pf_mem_supported) {
448626947304SEvan Yan 		(void) ndi_ra_free(ddi_get_parent(new_child),
448726947304SEvan Yan 		    pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
448826947304SEvan Yan 		    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
4489a6469d9bSprasad 
449026947304SEvan Yan 		if (pf_mem_end == pf_mem_answer) {
449126947304SEvan Yan 			DEBUG0("No PF memory resources used\n");
449226947304SEvan Yan 			/*
449326947304SEvan Yan 			 * To prevent the bridge from forwarding any PF Memory
449426947304SEvan Yan 			 * transactions, the PF Memory Limit will be programmed
449526947304SEvan Yan 			 * with a smaller value than the Memory Base.
449626947304SEvan Yan 			 */
449726947304SEvan Yan 			pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
449826947304SEvan Yan 			pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
449926947304SEvan Yan 			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
450026947304SEvan Yan 			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
4501a6469d9bSprasad 
450226947304SEvan Yan 			pf_mem_size = 0;
450326947304SEvan Yan 		} else {
450426947304SEvan Yan 			/*
450526947304SEvan Yan 			 * Reprogram the end of the PF memory range.
450626947304SEvan Yan 			 */
450726947304SEvan Yan 			pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
450826947304SEvan Yan 			    PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
450926947304SEvan Yan 			pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
451026947304SEvan Yan 			    PCICFG_HIADDR(pf_mem_end - 1));
451126947304SEvan Yan 			pf_mem_size = pf_mem_end - pf_mem_base;
451226947304SEvan Yan 		}
4513a6469d9bSprasad 	}
4514a6469d9bSprasad 
451570025d76Sjohnny 	if ((max_bus - *highest_bus) > 0) {
451670025d76Sjohnny 		/*
451770025d76Sjohnny 		 * Give back unused bus numbers
451870025d76Sjohnny 		 */
451970025d76Sjohnny 		(void) ndi_ra_free(ddi_get_parent(new_child),
452026947304SEvan Yan 		    *highest_bus+1, max_bus - *highest_bus,
452126947304SEvan Yan 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
452270025d76Sjohnny 	}
452370025d76Sjohnny 
452470025d76Sjohnny 	/*
452570025d76Sjohnny 	 * Set bus numbers to ranges encountered during scan
452670025d76Sjohnny 	 */
452770025d76Sjohnny 	(void) pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
452870025d76Sjohnny 
452970025d76Sjohnny 	/*
453070025d76Sjohnny 	 * Remove the ranges property if it exists since we will create
453170025d76Sjohnny 	 * a new one.
453270025d76Sjohnny 	 */
453370025d76Sjohnny 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
453470025d76Sjohnny 
453570025d76Sjohnny 	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
453670025d76Sjohnny 	    mem_base, mem_size);
453770025d76Sjohnny 	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
453870025d76Sjohnny 	    io_base, io_size);
4539a6469d9bSprasad 	DEBUG2("                         - PF Mem address %lx PF Mem Size %x\n",
4540a6469d9bSprasad 	    pf_mem_base, pf_mem_size);
454170025d76Sjohnny 
454200d0963fSdilpreet 	bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
454370025d76Sjohnny 
454400d0963fSdilpreet 	range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
454500d0963fSdilpreet 	    PCI_ADDR_IO);
454600d0963fSdilpreet 	range[0].child_low = range[0].parent_low = io_base;
454700d0963fSdilpreet 	range[1].child_high = range[1].parent_high |=
454870025d76Sjohnny 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
454900d0963fSdilpreet 	range[1].child_low = range[1].parent_low = mem_base;
455000d0963fSdilpreet 	range[2].child_high = range[2].parent_high |=
4551a6469d9bSprasad 	    (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
455200d0963fSdilpreet 	range[2].child_low = range[2].parent_low = pf_mem_base;
455370025d76Sjohnny 
455470025d76Sjohnny 	if (io_size > 0) {
455500d0963fSdilpreet 		range[0].size_low = io_size;
4556a6469d9bSprasad 		(void) pcicfg_update_ranges_prop(new_child, &range[0]);
455770025d76Sjohnny 	}
455870025d76Sjohnny 	if (mem_size > 0) {
455900d0963fSdilpreet 		range[1].size_low = mem_size;
4560a6469d9bSprasad 		(void) pcicfg_update_ranges_prop(new_child, &range[1]);
4561a6469d9bSprasad 	}
4562a6469d9bSprasad 	if (pf_mem_size > 0) {
456300d0963fSdilpreet 		range[2].size_low = pf_mem_size;
4564a6469d9bSprasad 		(void) pcicfg_update_ranges_prop(new_child, &range[2]);
456570025d76Sjohnny 	}
456670025d76Sjohnny 
456770025d76Sjohnny 	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
456870025d76Sjohnny 	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
456970025d76Sjohnny 	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
457070025d76Sjohnny 	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
457170025d76Sjohnny 
4572a6469d9bSprasad 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
4573a6469d9bSprasad 	    "bus-range", bus_range, 2);
457470025d76Sjohnny 
4575a6469d9bSprasad 	rval = PCICFG_SUCCESS;
457670025d76Sjohnny 
4577a6469d9bSprasad 	PCICFG_DUMP_BRIDGE_CONFIG(h);
457870025d76Sjohnny 
4579a6469d9bSprasad cleanup:
4580a6469d9bSprasad 	/* free up resources (for error return case only) */
4581a6469d9bSprasad 	if (rval != PCICFG_SUCCESS) {
458226947304SEvan Yan 		if (mem_alen)
458326947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
458426947304SEvan Yan 			    mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
458526947304SEvan Yan 		if (io_alen)
458626947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child), io_base,
458726947304SEvan Yan 			    io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
458826947304SEvan Yan 		if (pf_mem_alen)
458926947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child),
459026947304SEvan Yan 			    pf_mem_base, pf_mem_alen,
459126947304SEvan Yan 			    NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
459226947304SEvan Yan 		if (pcibus_alen)
459326947304SEvan Yan 			(void) ndi_ra_free(ddi_get_parent(new_child),
459426947304SEvan Yan 			    pcibus_base, pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM,
459526947304SEvan Yan 			    NDI_RA_PASS);
4596a6469d9bSprasad 	}
4597a6469d9bSprasad 
4598a6469d9bSprasad 	/* free up any resource maps setup for the bridge node */
4599a6469d9bSprasad 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM);
4600a6469d9bSprasad 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO);
4601a6469d9bSprasad 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM);
4602a6469d9bSprasad 	(void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM);
4603a6469d9bSprasad 
4604a6469d9bSprasad 	return (rval);
460570025d76Sjohnny }
460670025d76Sjohnny 
460770025d76Sjohnny static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)460870025d76Sjohnny pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
460970025d76Sjohnny {
461070025d76Sjohnny 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
461170025d76Sjohnny 	pci_regspec_t *pci_ap;
461270025d76Sjohnny 	int length;
461370025d76Sjohnny 	int rcount;
461470025d76Sjohnny 	int i;
461570025d76Sjohnny 
461670025d76Sjohnny 	entry->error = PCICFG_SUCCESS;
461770025d76Sjohnny 
461870025d76Sjohnny 	if (dip == entry->dip) {
461970025d76Sjohnny 		DEBUG0("Don't include parent bridge node\n");
462070025d76Sjohnny 		return (DDI_WALK_CONTINUE);
462170025d76Sjohnny 	} else {
462270025d76Sjohnny 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
462370025d76Sjohnny 		    DDI_PROP_DONTPASS, "assigned-addresses",
462470025d76Sjohnny 		    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
462570025d76Sjohnny 			DEBUG0("Node doesn't have assigned-addresses\n");
462670025d76Sjohnny 			return (DDI_WALK_CONTINUE);
462770025d76Sjohnny 		}
462870025d76Sjohnny 
462970025d76Sjohnny 		rcount = length / sizeof (pci_regspec_t);
463070025d76Sjohnny 
463170025d76Sjohnny 		for (i = 0; i < rcount; i++) {
463270025d76Sjohnny 
463370025d76Sjohnny 			switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
463470025d76Sjohnny 
463570025d76Sjohnny 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
463626947304SEvan Yan 				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
463726947304SEvan Yan 					if ((pci_ap[i].pci_phys_low +
463826947304SEvan Yan 					    pci_ap[i].pci_size_low) >
463926947304SEvan Yan 					    entry->pf_memory_base) {
464026947304SEvan Yan 						entry->pf_memory_base =
464126947304SEvan Yan 						    pci_ap[i].pci_phys_low +
464226947304SEvan Yan 						    pci_ap[i].pci_size_low;
464326947304SEvan Yan 					}
464426947304SEvan Yan 				} else {
464526947304SEvan Yan 					if ((pci_ap[i].pci_phys_low +
464626947304SEvan Yan 					    pci_ap[i].pci_size_low) >
464726947304SEvan Yan 					    entry->memory_base) {
464826947304SEvan Yan 						entry->memory_base =
464926947304SEvan Yan 						    pci_ap[i].pci_phys_low +
465026947304SEvan Yan 						    pci_ap[i].pci_size_low;
465126947304SEvan Yan 					}
465270025d76Sjohnny 				}
465326947304SEvan Yan 				break;
465470025d76Sjohnny 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
465526947304SEvan Yan 				if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
465626947304SEvan Yan 					if ((PCICFG_LADDR(
4657a6469d9bSprasad 					    pci_ap[i].pci_phys_low,
4658a6469d9bSprasad 					    pci_ap[i].pci_phys_mid) +
465926947304SEvan Yan 					    pci_ap[i].pci_size_low) >
466026947304SEvan Yan 					    entry->pf_memory_base) {
466126947304SEvan Yan 						entry->pf_memory_base =
466226947304SEvan Yan 						    PCICFG_LADDR(
466326947304SEvan Yan 						    pci_ap[i].pci_phys_low,
466426947304SEvan Yan 						    pci_ap[i].pci_phys_mid) +
466526947304SEvan Yan 						    pci_ap[i].pci_size_low;
466626947304SEvan Yan 					}
466726947304SEvan Yan 				} else {
466826947304SEvan Yan 					if ((PCICFG_LADDR(
466970025d76Sjohnny 					    pci_ap[i].pci_phys_low,
467070025d76Sjohnny 					    pci_ap[i].pci_phys_mid) +
467126947304SEvan Yan 					    pci_ap[i].pci_size_low) >
467226947304SEvan Yan 					    entry->memory_base) {
467326947304SEvan Yan 						entry->memory_base =
467426947304SEvan Yan 						    PCICFG_LADDR(
467526947304SEvan Yan 						    pci_ap[i].pci_phys_low,
467626947304SEvan Yan 						    pci_ap[i].pci_phys_mid) +
467726947304SEvan Yan 						    pci_ap[i].pci_size_low;
467826947304SEvan Yan 					}
467970025d76Sjohnny 				}
468026947304SEvan Yan 				break;
468170025d76Sjohnny 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
468270025d76Sjohnny 				if ((pci_ap[i].pci_phys_low +
468370025d76Sjohnny 				    pci_ap[i].pci_size_low) >
468470025d76Sjohnny 				    entry->io_base) {
468570025d76Sjohnny 					entry->io_base =
468670025d76Sjohnny 					    pci_ap[i].pci_phys_low +
468770025d76Sjohnny 					    pci_ap[i].pci_size_low;
468870025d76Sjohnny 				}
468926947304SEvan Yan 				break;
469070025d76Sjohnny 			}
469170025d76Sjohnny 		}
469270025d76Sjohnny 
469370025d76Sjohnny 		/*
469470025d76Sjohnny 		 * free the memory allocated by ddi_getlongprop
469570025d76Sjohnny 		 */
469670025d76Sjohnny 		kmem_free(pci_ap, length);
469770025d76Sjohnny 
469870025d76Sjohnny 		/*
469970025d76Sjohnny 		 * continue the walk to the next sibling to sum memory
470070025d76Sjohnny 		 */
470170025d76Sjohnny 		return (DDI_WALK_CONTINUE);
470270025d76Sjohnny 	}
470370025d76Sjohnny }
470470025d76Sjohnny 
47057c478bd9Sstevel@tonic-gate /*
47067c478bd9Sstevel@tonic-gate  * Make "parent" be the parent of the "child" dip
47077c478bd9Sstevel@tonic-gate  */
47087c478bd9Sstevel@tonic-gate static void
pcicfg_reparent_node(dev_info_t * child,dev_info_t * parent)47097c478bd9Sstevel@tonic-gate pcicfg_reparent_node(dev_info_t *child, dev_info_t *parent)
47107c478bd9Sstevel@tonic-gate {
47117c478bd9Sstevel@tonic-gate 	dev_info_t *opdip;
47127c478bd9Sstevel@tonic-gate 
47137c478bd9Sstevel@tonic-gate 	ASSERT(i_ddi_node_state(child) <= DS_LINKED);
47147c478bd9Sstevel@tonic-gate 	/*
47157c478bd9Sstevel@tonic-gate 	 * Unlink node from tree before reparenting
47167c478bd9Sstevel@tonic-gate 	 */
47177c478bd9Sstevel@tonic-gate 	opdip = ddi_get_parent(child);
47183fe80ca4SDan Cross 	ndi_devi_enter(opdip);
47197c478bd9Sstevel@tonic-gate 	(void) i_ndi_unconfig_node(child, DS_PROTO, 0);
47203fe80ca4SDan Cross 	ndi_devi_exit(opdip);
47217c478bd9Sstevel@tonic-gate 
47227c478bd9Sstevel@tonic-gate 	DEVI(child)->devi_parent = DEVI(parent);
47237c478bd9Sstevel@tonic-gate 	DEVI(child)->devi_bus_ctl = DEVI(parent);
47247c478bd9Sstevel@tonic-gate 	(void) ndi_devi_bind_driver(child, 0);
47257c478bd9Sstevel@tonic-gate }
47267c478bd9Sstevel@tonic-gate 
47277c478bd9Sstevel@tonic-gate /*
47287c478bd9Sstevel@tonic-gate  * Return PCICFG_SUCCESS if device exists at the specified address.
47297c478bd9Sstevel@tonic-gate  * Return PCICFG_NODEVICE is no device exists at the specified address.
47307c478bd9Sstevel@tonic-gate  */
47317c478bd9Sstevel@tonic-gate int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)47327c478bd9Sstevel@tonic-gate pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
47337c478bd9Sstevel@tonic-gate {
47347c478bd9Sstevel@tonic-gate 	caddr_t	cfgaddr;
47357c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
47367c478bd9Sstevel@tonic-gate 	dev_info_t *anode;
47377c478bd9Sstevel@tonic-gate 	int status;
47387c478bd9Sstevel@tonic-gate 	int		rlen;
47397c478bd9Sstevel@tonic-gate 	pci_regspec_t	*reg;
47407c478bd9Sstevel@tonic-gate 	int		ret = DDI_SUCCESS;
47417c478bd9Sstevel@tonic-gate 	int16_t		tmp;
47427c478bd9Sstevel@tonic-gate 
47437c478bd9Sstevel@tonic-gate 	/*
47447c478bd9Sstevel@tonic-gate 	 * Get the pci register spec from the node
47457c478bd9Sstevel@tonic-gate 	 */
474626947304SEvan Yan 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
474726947304SEvan Yan 	    (caddr_t)&reg, &rlen);
47487c478bd9Sstevel@tonic-gate 
47497c478bd9Sstevel@tonic-gate 	switch (status) {
47507c478bd9Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
475126947304SEvan Yan 			break;
47527c478bd9Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
47537c478bd9Sstevel@tonic-gate 			DEBUG0("reg present, but unable to get memory\n");
47547c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
47557c478bd9Sstevel@tonic-gate 		default:
47567c478bd9Sstevel@tonic-gate 			DEBUG0("no reg property\n");
47577c478bd9Sstevel@tonic-gate 			return (PCICFG_FAILURE);
47587c478bd9Sstevel@tonic-gate 	}
47597c478bd9Sstevel@tonic-gate 
47607c478bd9Sstevel@tonic-gate 	anode = dip;
476123c35297Sanish 	DEBUG2("conf_map: dip=%p, anode=%p\n", dip, anode);
47627c478bd9Sstevel@tonic-gate 
47637c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
47647c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
47657c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
47667c478bd9Sstevel@tonic-gate 
476726947304SEvan Yan 	if (ddi_regs_map_setup(anode, 0, &cfgaddr, 0, 0, &attr, handle)
476826947304SEvan Yan 	    != DDI_SUCCESS) {
47697c478bd9Sstevel@tonic-gate 		DEBUG0("Failed to setup registers\n");
47707c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)reg, rlen);
47717c478bd9Sstevel@tonic-gate 		return (PCICFG_FAILURE);
47727c478bd9Sstevel@tonic-gate 	}
47737c478bd9Sstevel@tonic-gate 
477423c35297Sanish 	/*
477523c35297Sanish 	 * need to use DDI interfaces as the conf space is
477623c35297Sanish 	 * cannot be directly accessed by the host.
477723c35297Sanish 	 */
477823c35297Sanish 	tmp = (int16_t)ddi_get16(*handle, (uint16_t *)cfgaddr);
477923c35297Sanish 	if ((tmp == (int16_t)0xffff) || (tmp == -1)) {
478023c35297Sanish 		DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
478123c35297Sanish 		ret = PCICFG_NODEVICE;
47827c478bd9Sstevel@tonic-gate 	} else {
478323c35297Sanish 		if (tmp == 0) {
478423c35297Sanish 			DEBUG0("Device Not Ready yet ?");
47857c478bd9Sstevel@tonic-gate 			ret = PCICFG_NODEVICE;
47867c478bd9Sstevel@tonic-gate 		} else {
478723c35297Sanish 			DEBUG1("DEVICEFOUND, read %x\n", tmp);
478823c35297Sanish 			ret = PCICFG_SUCCESS;
47897c478bd9Sstevel@tonic-gate 		}
47907c478bd9Sstevel@tonic-gate 	}
47917c478bd9Sstevel@tonic-gate 
47927c478bd9Sstevel@tonic-gate 	if (ret == PCICFG_NODEVICE)
47937c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(handle);
47947c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)reg, rlen);
47957c478bd9Sstevel@tonic-gate 
47967c478bd9Sstevel@tonic-gate 	return (ret);
47977c478bd9Sstevel@tonic-gate 
47987c478bd9Sstevel@tonic-gate }
47997c478bd9Sstevel@tonic-gate 
48007c478bd9Sstevel@tonic-gate static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)48017c478bd9Sstevel@tonic-gate pcicfg_config_teardown(ddi_acc_handle_t *handle)
48027c478bd9Sstevel@tonic-gate {
48037c478bd9Sstevel@tonic-gate 	(void) ddi_regs_map_free(handle);
48047c478bd9Sstevel@tonic-gate }
48057c478bd9Sstevel@tonic-gate 
48067c478bd9Sstevel@tonic-gate static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)48077c478bd9Sstevel@tonic-gate pcicfg_add_config_reg(dev_info_t *dip,
4808ffb64830SJordan Paige Hendricks     uint_t bus, uint_t device, uint_t func)
48097c478bd9Sstevel@tonic-gate {
48107c478bd9Sstevel@tonic-gate 	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
48117c478bd9Sstevel@tonic-gate 
48127c478bd9Sstevel@tonic-gate 	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
48137c478bd9Sstevel@tonic-gate 
481426947304SEvan Yan 	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", reg, 5));
48157c478bd9Sstevel@tonic-gate }
48167c478bd9Sstevel@tonic-gate 
481726947304SEvan Yan static int
pcicfg_ari_configure(dev_info_t * dip)481826947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip)
481926947304SEvan Yan {
482026947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
482126947304SEvan Yan 		return (DDI_FAILURE);
482226947304SEvan Yan 
482326947304SEvan Yan 	/*
482426947304SEvan Yan 	 * Until we have resource balancing, dynamically configure
482526947304SEvan Yan 	 * ARI functions without firmware assistamce.
482626947304SEvan Yan 	 */
482726947304SEvan Yan 	return (DDI_FAILURE);
482826947304SEvan Yan }
482926947304SEvan Yan 
483026947304SEvan Yan 
48317c478bd9Sstevel@tonic-gate #ifdef DEBUG
48327c478bd9Sstevel@tonic-gate static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)4833ffb64830SJordan Paige Hendricks debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
4834ffb64830SJordan Paige Hendricks     uintptr_t a5)
48357c478bd9Sstevel@tonic-gate {
48367c478bd9Sstevel@tonic-gate 	if (pcicfg_debug > 1) {
48377c478bd9Sstevel@tonic-gate 		prom_printf("pcicfg: ");
48387c478bd9Sstevel@tonic-gate 		prom_printf(fmt, a1, a2, a3, a4, a5);
48397c478bd9Sstevel@tonic-gate 	}
48407c478bd9Sstevel@tonic-gate }
48417c478bd9Sstevel@tonic-gate #endif
48427c478bd9Sstevel@tonic-gate 
484370025d76Sjohnny /*ARGSUSED*/
484470025d76Sjohnny static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)484570025d76Sjohnny pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
484670025d76Sjohnny {
484749fbdd30SErwin T Tsaur 	uint16_t cap_id_loc, slot_id_loc;
484870025d76Sjohnny 	uint8_t num_slots = 0;
484970025d76Sjohnny 
485070025d76Sjohnny 	/* just depend on the pcie_cap for now. */
485149fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
485249fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &slot_id_loc);
485349fbdd30SErwin T Tsaur 	if (cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
485426947304SEvan Yan 		if (pci_config_get8(handle, cap_id_loc + PCI_CAP_ID_REGS_OFF) &
485526947304SEvan Yan 		    PCIE_PCIECAP_SLOT_IMPL)
485670025d76Sjohnny 			num_slots = 1;
485770025d76Sjohnny 	} else /* not a PCIe switch/bridge. Must be a PCI-PCI[-X] bridge */
485849fbdd30SErwin T Tsaur 	if (slot_id_loc != PCI_CAP_NEXT_PTR_NULL) {
485949fbdd30SErwin T Tsaur 		uint8_t esr_reg = pci_config_get8(handle, slot_id_loc + 2);
486070025d76Sjohnny 		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
486170025d76Sjohnny 	}
486270025d76Sjohnny 	/* XXX - need to cover PCI-PCIe bridge with n slots */
486370025d76Sjohnny 	return (num_slots);
486470025d76Sjohnny }
486570025d76Sjohnny 
486670025d76Sjohnny static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)486770025d76Sjohnny pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
486870025d76Sjohnny {
486970025d76Sjohnny 	int port_type = pcicfg_pcie_port_type(dip, handle);
487070025d76Sjohnny 
487170025d76Sjohnny 	DEBUG1("device port_type = %x\n", port_type);
487270025d76Sjohnny 	/* No PCIe CAP regs, we are not PCIe device_type */
487370025d76Sjohnny 	if (port_type < 0)
487470025d76Sjohnny 		return (DDI_FAILURE);
487570025d76Sjohnny 
487670025d76Sjohnny 	/* check for all PCIe device_types */
487770025d76Sjohnny 	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
487826947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
487926947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
488026947304SEvan Yan 	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
488170025d76Sjohnny 		return (DDI_SUCCESS);
488270025d76Sjohnny 
488370025d76Sjohnny 	return (DDI_FAILURE);
488470025d76Sjohnny 
488570025d76Sjohnny }
488670025d76Sjohnny 
488770025d76Sjohnny /*ARGSUSED*/
488870025d76Sjohnny static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)488970025d76Sjohnny pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
489070025d76Sjohnny {
489170025d76Sjohnny 	int port_type = -1;
489249fbdd30SErwin T Tsaur 	uint16_t cap_loc;
489370025d76Sjohnny 
489470025d76Sjohnny 	/* Note: need to look at the port type information here */
489549fbdd30SErwin T Tsaur 	(void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_loc);
489649fbdd30SErwin T Tsaur 	if (cap_loc != PCI_CAP_NEXT_PTR_NULL)
489770025d76Sjohnny 		port_type = pci_config_get16(handle,
489826947304SEvan Yan 		    cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
489970025d76Sjohnny 
490070025d76Sjohnny 	return (port_type);
490170025d76Sjohnny }
4902c0da6274SZhi-Jun Robin Fu 
4903c0da6274SZhi-Jun Robin Fu /*
4904c0da6274SZhi-Jun Robin Fu  * Return true if the devinfo node is in a PCI Express hierarchy.
4905c0da6274SZhi-Jun Robin Fu  */
4906c0da6274SZhi-Jun Robin Fu static boolean_t
is_pcie_fabric(dev_info_t * dip)4907c0da6274SZhi-Jun Robin Fu is_pcie_fabric(dev_info_t *dip)
4908c0da6274SZhi-Jun Robin Fu {
4909c0da6274SZhi-Jun Robin Fu 	dev_info_t *root = ddi_root_node();
4910c0da6274SZhi-Jun Robin Fu 	dev_info_t *pdip;
4911c0da6274SZhi-Jun Robin Fu 	boolean_t found = B_FALSE;
4912c0da6274SZhi-Jun Robin Fu 	char *bus;
4913c0da6274SZhi-Jun Robin Fu 
4914c0da6274SZhi-Jun Robin Fu 	/*
4915c0da6274SZhi-Jun Robin Fu 	 * Does this device reside in a pcie fabric ?
4916c0da6274SZhi-Jun Robin Fu 	 */
4917c0da6274SZhi-Jun Robin Fu 	for (pdip = dip; pdip && (pdip != root) && !found;
4918c0da6274SZhi-Jun Robin Fu 	    pdip = ddi_get_parent(pdip)) {
4919c0da6274SZhi-Jun Robin Fu 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
4920c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_DONTPASS, "device_type", &bus) !=
4921c0da6274SZhi-Jun Robin Fu 		    DDI_PROP_SUCCESS)
4922c0da6274SZhi-Jun Robin Fu 			break;
4923c0da6274SZhi-Jun Robin Fu 
4924c0da6274SZhi-Jun Robin Fu 		if (strcmp(bus, "pciex") == 0)
4925c0da6274SZhi-Jun Robin Fu 			found = B_TRUE;
4926c0da6274SZhi-Jun Robin Fu 
4927c0da6274SZhi-Jun Robin Fu 		ddi_prop_free(bus);
4928c0da6274SZhi-Jun Robin Fu 	}
4929c0da6274SZhi-Jun Robin Fu 
4930c0da6274SZhi-Jun Robin Fu 	return (found);
4931c0da6274SZhi-Jun Robin Fu }
4932