xref: /onnv-gate/usr/src/uts/sun4/io/pcicfg.c (revision 12765:c3482aaf193f)
110923SEvan.Yan@Sun.COM /*
210923SEvan.Yan@Sun.COM  * CDDL HEADER START
310923SEvan.Yan@Sun.COM  *
410923SEvan.Yan@Sun.COM  * The contents of this file are subject to the terms of the
510923SEvan.Yan@Sun.COM  * Common Development and Distribution License (the "License").
610923SEvan.Yan@Sun.COM  * You may not use this file except in compliance with the License.
710923SEvan.Yan@Sun.COM  *
810923SEvan.Yan@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910923SEvan.Yan@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010923SEvan.Yan@Sun.COM  * See the License for the specific language governing permissions
1110923SEvan.Yan@Sun.COM  * and limitations under the License.
1210923SEvan.Yan@Sun.COM  *
1310923SEvan.Yan@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410923SEvan.Yan@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510923SEvan.Yan@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610923SEvan.Yan@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710923SEvan.Yan@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810923SEvan.Yan@Sun.COM  *
1910923SEvan.Yan@Sun.COM  * CDDL HEADER END
2010923SEvan.Yan@Sun.COM  */
2110923SEvan.Yan@Sun.COM /*
2212622SAlan.Adamson@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2310923SEvan.Yan@Sun.COM  */
2410923SEvan.Yan@Sun.COM 
2510923SEvan.Yan@Sun.COM /*
2610923SEvan.Yan@Sun.COM  *     PCI configurator (pcicfg)
2710923SEvan.Yan@Sun.COM  */
2810923SEvan.Yan@Sun.COM 
2910923SEvan.Yan@Sun.COM #include <sys/isa_defs.h>
3010923SEvan.Yan@Sun.COM 
3110923SEvan.Yan@Sun.COM #include <sys/conf.h>
3210923SEvan.Yan@Sun.COM #include <sys/kmem.h>
3310923SEvan.Yan@Sun.COM #include <sys/debug.h>
3410923SEvan.Yan@Sun.COM #include <sys/modctl.h>
3510923SEvan.Yan@Sun.COM #include <sys/autoconf.h>
3610923SEvan.Yan@Sun.COM #include <sys/hwconf.h>
3710923SEvan.Yan@Sun.COM #include <sys/ddi_impldefs.h>
3810923SEvan.Yan@Sun.COM #include <sys/fcode.h>
3910923SEvan.Yan@Sun.COM #include <sys/pci.h>
4010923SEvan.Yan@Sun.COM #include <sys/pcie.h>
4110923SEvan.Yan@Sun.COM #include <sys/pcie_impl.h>
4210923SEvan.Yan@Sun.COM #include <sys/ddi.h>
4310923SEvan.Yan@Sun.COM #include <sys/sunddi.h>
4410923SEvan.Yan@Sun.COM #include <sys/sunndi.h>
4510923SEvan.Yan@Sun.COM #include <sys/pci_cap.h>
4610923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h>
4710923SEvan.Yan@Sun.COM #include <sys/ndi_impldefs.h>
4811245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
4910923SEvan.Yan@Sun.COM 
5010923SEvan.Yan@Sun.COM #define	PCICFG_DEVICE_TYPE_PCI	1
5110923SEvan.Yan@Sun.COM #define	PCICFG_DEVICE_TYPE_PCIE	2
5210923SEvan.Yan@Sun.COM 
5310923SEvan.Yan@Sun.COM #define	EFCODE21554	/* changes for supporting 21554 */
5410923SEvan.Yan@Sun.COM 
5510923SEvan.Yan@Sun.COM static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t);
5610923SEvan.Yan@Sun.COM static int pcicfg_free_resource(dev_info_t *, pci_regspec_t, pcicfg_flags_t);
5710923SEvan.Yan@Sun.COM static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
5810923SEvan.Yan@Sun.COM 
5910923SEvan.Yan@Sun.COM #ifdef	PCICFG_INTERPRET_FCODE
6010923SEvan.Yan@Sun.COM static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *,
6110923SEvan.Yan@Sun.COM     uint_t, uint_t, uint_t, int32_t, pci_regspec_t *);
6210923SEvan.Yan@Sun.COM #endif	/* PCICFG_INTERPRET_FCODE */
6310923SEvan.Yan@Sun.COM 
6410923SEvan.Yan@Sun.COM /*
6510923SEvan.Yan@Sun.COM  * ************************************************************************
6610923SEvan.Yan@Sun.COM  * *** Implementation specific local data structures/definitions.	***
6710923SEvan.Yan@Sun.COM  * ************************************************************************
6810923SEvan.Yan@Sun.COM  */
6910923SEvan.Yan@Sun.COM 
7010923SEvan.Yan@Sun.COM static	int	pcicfg_start_devno = 0;	/* for Debug only */
7110923SEvan.Yan@Sun.COM 
7210923SEvan.Yan@Sun.COM #define	PCICFG_MAX_DEVICE 32
7310923SEvan.Yan@Sun.COM #define	PCICFG_MAX_FUNCTION 8
7410923SEvan.Yan@Sun.COM #define	PCICFG_MAX_ARI_FUNCTION 256
7510923SEvan.Yan@Sun.COM #define	PCICFG_MAX_REGISTER 64
7610923SEvan.Yan@Sun.COM #define	PCICFG_MAX_BUS_DEPTH 255
7710923SEvan.Yan@Sun.COM 
7810923SEvan.Yan@Sun.COM #define	PCICFG_NODEVICE 42
7910923SEvan.Yan@Sun.COM #define	PCICFG_NOMEMORY 43
8010923SEvan.Yan@Sun.COM #define	PCICFG_NOMULTI	44
8110923SEvan.Yan@Sun.COM 
8210923SEvan.Yan@Sun.COM #define	PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
8310923SEvan.Yan@Sun.COM #define	PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
8410923SEvan.Yan@Sun.COM #define	PCICFG_LADDR(lo, hi)	(((uint64_t)(hi) << 32) | (uint32_t)(lo))
8510923SEvan.Yan@Sun.COM 
8610923SEvan.Yan@Sun.COM #define	PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
8710923SEvan.Yan@Sun.COM #define	PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
8810923SEvan.Yan@Sun.COM #define	PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
8910923SEvan.Yan@Sun.COM #define	PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
9010923SEvan.Yan@Sun.COM 
9110923SEvan.Yan@Sun.COM #define	PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
9210923SEvan.Yan@Sun.COM #define	PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
9310923SEvan.Yan@Sun.COM 
9410923SEvan.Yan@Sun.COM #define	PCICFG_MEMGRAN 0x100000
9510923SEvan.Yan@Sun.COM #define	PCICFG_IOGRAN 0x1000
9610923SEvan.Yan@Sun.COM #define	PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
9710923SEvan.Yan@Sun.COM 
9810923SEvan.Yan@Sun.COM #define	PCICFG_MEM_MULT 4
9910923SEvan.Yan@Sun.COM #define	PCICFG_IO_MULT 4
10010923SEvan.Yan@Sun.COM #define	PCICFG_RANGE_LEN 2 /* Number of range entries */
10110923SEvan.Yan@Sun.COM 
10210923SEvan.Yan@Sun.COM static int pcicfg_slot_busnums = 8;
10310923SEvan.Yan@Sun.COM static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
10410923SEvan.Yan@Sun.COM static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */
10510923SEvan.Yan@Sun.COM static int pcicfg_chassis_per_tree = 1;
10610923SEvan.Yan@Sun.COM static int pcicfg_sec_reset_delay = 1000000;
10710923SEvan.Yan@Sun.COM 
10810923SEvan.Yan@Sun.COM /*
10910923SEvan.Yan@Sun.COM  * The following typedef is used to represent a
11010923SEvan.Yan@Sun.COM  * 1275 "bus-range" property of a PCI Bus node.
11110923SEvan.Yan@Sun.COM  * DAF - should be in generic include file...
11210923SEvan.Yan@Sun.COM  */
11310923SEvan.Yan@Sun.COM 
11410923SEvan.Yan@Sun.COM typedef struct pcicfg_bus_range {
11510923SEvan.Yan@Sun.COM 	uint32_t lo;
11610923SEvan.Yan@Sun.COM 	uint32_t hi;
11710923SEvan.Yan@Sun.COM } pcicfg_bus_range_t;
11810923SEvan.Yan@Sun.COM 
11910923SEvan.Yan@Sun.COM typedef struct pcicfg_range {
12010923SEvan.Yan@Sun.COM 
12110923SEvan.Yan@Sun.COM 	uint32_t child_hi;
12210923SEvan.Yan@Sun.COM 	uint32_t child_mid;
12310923SEvan.Yan@Sun.COM 	uint32_t child_lo;
12410923SEvan.Yan@Sun.COM 	uint32_t parent_hi;
12510923SEvan.Yan@Sun.COM 	uint32_t parent_mid;
12610923SEvan.Yan@Sun.COM 	uint32_t parent_lo;
12710923SEvan.Yan@Sun.COM 	uint32_t size_hi;
12810923SEvan.Yan@Sun.COM 	uint32_t size_lo;
12910923SEvan.Yan@Sun.COM 
13010923SEvan.Yan@Sun.COM } pcicfg_range_t;
13110923SEvan.Yan@Sun.COM 
13210923SEvan.Yan@Sun.COM typedef struct hole hole_t;
13310923SEvan.Yan@Sun.COM 
13410923SEvan.Yan@Sun.COM struct hole {
13510923SEvan.Yan@Sun.COM 	uint64_t	start;
13610923SEvan.Yan@Sun.COM 	uint64_t	len;
13710923SEvan.Yan@Sun.COM 	hole_t		*next;
13810923SEvan.Yan@Sun.COM };
13910923SEvan.Yan@Sun.COM 
14010923SEvan.Yan@Sun.COM typedef struct pcicfg_phdl pcicfg_phdl_t;
14110923SEvan.Yan@Sun.COM 
14210923SEvan.Yan@Sun.COM struct pcicfg_phdl {
14310923SEvan.Yan@Sun.COM 
14410923SEvan.Yan@Sun.COM 	dev_info_t	*dip;		/* Associated with the attach point */
14510923SEvan.Yan@Sun.COM 	pcicfg_phdl_t	*next;
14610923SEvan.Yan@Sun.COM 
14710923SEvan.Yan@Sun.COM 	uint64_t	memory_base;	/* Memory base for this attach point */
14810923SEvan.Yan@Sun.COM 	uint64_t	memory_last;
14910923SEvan.Yan@Sun.COM 	uint64_t	memory_len;
15010923SEvan.Yan@Sun.COM 	uint32_t	io_base;	/* I/O base for this attach point */
15110923SEvan.Yan@Sun.COM 	uint32_t	io_last;
15210923SEvan.Yan@Sun.COM 	uint32_t	io_len;
15310923SEvan.Yan@Sun.COM 
15410923SEvan.Yan@Sun.COM 	int		error;
15510923SEvan.Yan@Sun.COM 	uint_t		highest_bus;	/* Highest bus seen on the probe */
15610923SEvan.Yan@Sun.COM 
15710923SEvan.Yan@Sun.COM 	hole_t		mem_hole;	/* Memory hole linked list. */
15810923SEvan.Yan@Sun.COM 	hole_t		io_hole;	/* IO hole linked list */
15910923SEvan.Yan@Sun.COM 
16010923SEvan.Yan@Sun.COM 	ndi_ra_request_t mem_req;	/* allocator request for memory */
16110923SEvan.Yan@Sun.COM 	ndi_ra_request_t io_req;	/* allocator request for I/O */
16210923SEvan.Yan@Sun.COM };
16310923SEvan.Yan@Sun.COM 
16410923SEvan.Yan@Sun.COM struct pcicfg_standard_prop_entry {
16510923SEvan.Yan@Sun.COM     uchar_t *name;
16610923SEvan.Yan@Sun.COM     uint_t  config_offset;
16710923SEvan.Yan@Sun.COM     uint_t  size;
16810923SEvan.Yan@Sun.COM };
16910923SEvan.Yan@Sun.COM 
17010923SEvan.Yan@Sun.COM 
17110923SEvan.Yan@Sun.COM struct pcicfg_name_entry {
17210923SEvan.Yan@Sun.COM     uint32_t class_code;
17310923SEvan.Yan@Sun.COM     char  *name;
17410923SEvan.Yan@Sun.COM };
17510923SEvan.Yan@Sun.COM 
17610923SEvan.Yan@Sun.COM struct pcicfg_find_ctrl {
17710923SEvan.Yan@Sun.COM 	uint_t		device;
17810923SEvan.Yan@Sun.COM 	uint_t		function;
17910923SEvan.Yan@Sun.COM 	dev_info_t	*dip;
18010923SEvan.Yan@Sun.COM };
18110923SEvan.Yan@Sun.COM 
18210923SEvan.Yan@Sun.COM typedef struct pcicfg_err_regs {
18310923SEvan.Yan@Sun.COM 	uint16_t cmd;
18410923SEvan.Yan@Sun.COM 	uint16_t bcntl;
18510923SEvan.Yan@Sun.COM 	uint16_t pcie_dev;
18610923SEvan.Yan@Sun.COM 	uint16_t devctl;
18710923SEvan.Yan@Sun.COM 	uint16_t pcie_cap_off;
18810923SEvan.Yan@Sun.COM } pcicfg_err_regs_t;
18910923SEvan.Yan@Sun.COM 
19010923SEvan.Yan@Sun.COM /*
19110923SEvan.Yan@Sun.COM  * List of Indirect Config Map Devices. At least the intent of the
19210923SEvan.Yan@Sun.COM  * design is to look for a device in this list during the configure
19310923SEvan.Yan@Sun.COM  * operation, and if the device is listed here, then it is a nontransparent
19410923SEvan.Yan@Sun.COM  * bridge, hence load the driver and avail the config map services from
19510923SEvan.Yan@Sun.COM  * the driver. Class and Subclass should be as defined in the PCI specs
19610923SEvan.Yan@Sun.COM  * ie. class is 0x6, and subclass is 0x9.
19710923SEvan.Yan@Sun.COM  */
19810923SEvan.Yan@Sun.COM static struct {
19910923SEvan.Yan@Sun.COM 	uint8_t		mem_range_bar_offset;
20010923SEvan.Yan@Sun.COM 	uint8_t		io_range_bar_offset;
20110923SEvan.Yan@Sun.COM 	uint8_t		prefetch_mem_range_bar_offset;
20210923SEvan.Yan@Sun.COM } pcicfg_indirect_map_devs[] = {
20310923SEvan.Yan@Sun.COM 	PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
20410923SEvan.Yan@Sun.COM 	0,	0,	0,
20510923SEvan.Yan@Sun.COM };
20610923SEvan.Yan@Sun.COM 
20710923SEvan.Yan@Sun.COM #define	PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
20810923SEvan.Yan@Sun.COM 	(\
20910923SEvan.Yan@Sun.COM 	((ulong_t)(busnum & 0xff) << 16)    |\
21010923SEvan.Yan@Sun.COM 	((ulong_t)(devnum & 0x1f) << 11)    |\
21110923SEvan.Yan@Sun.COM 	((ulong_t)(funcnum & 0x7) <<  8)    |\
21210923SEvan.Yan@Sun.COM 	((ulong_t)(register & 0x3f)))
21310923SEvan.Yan@Sun.COM 
21410923SEvan.Yan@Sun.COM /*
21510923SEvan.Yan@Sun.COM  * debug macros:
21610923SEvan.Yan@Sun.COM  */
21710923SEvan.Yan@Sun.COM #if	defined(DEBUG)
21810923SEvan.Yan@Sun.COM extern void prom_printf(const char *, ...);
21910923SEvan.Yan@Sun.COM 
22010923SEvan.Yan@Sun.COM /*
22110923SEvan.Yan@Sun.COM  * Following values are defined for this debug flag.
22210923SEvan.Yan@Sun.COM  *
22310923SEvan.Yan@Sun.COM  * 1 = dump configuration header only.
22410923SEvan.Yan@Sun.COM  * 2 = dump generic debug data only (no config header dumped)
22510923SEvan.Yan@Sun.COM  * 3 = dump everything (both 1 and 2)
22610923SEvan.Yan@Sun.COM  */
22710923SEvan.Yan@Sun.COM int pcicfg_debug = 0;
22810923SEvan.Yan@Sun.COM int pcicfg_dump_fcode = 0;
22910923SEvan.Yan@Sun.COM 
23010923SEvan.Yan@Sun.COM static void debug(char *, uintptr_t, uintptr_t,
23110923SEvan.Yan@Sun.COM 	uintptr_t, uintptr_t, uintptr_t);
23210923SEvan.Yan@Sun.COM 
23310923SEvan.Yan@Sun.COM #define	DEBUG0(fmt)\
23410923SEvan.Yan@Sun.COM 	debug(fmt, 0, 0, 0, 0, 0);
23510923SEvan.Yan@Sun.COM #define	DEBUG1(fmt, a1)\
23610923SEvan.Yan@Sun.COM 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
23710923SEvan.Yan@Sun.COM #define	DEBUG2(fmt, a1, a2)\
23810923SEvan.Yan@Sun.COM 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
23910923SEvan.Yan@Sun.COM #define	DEBUG3(fmt, a1, a2, a3)\
24010923SEvan.Yan@Sun.COM 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
24110923SEvan.Yan@Sun.COM 		(uintptr_t)(a3), 0, 0);
24210923SEvan.Yan@Sun.COM #define	DEBUG4(fmt, a1, a2, a3, a4)\
24310923SEvan.Yan@Sun.COM 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
24410923SEvan.Yan@Sun.COM 		(uintptr_t)(a3), (uintptr_t)(a4), 0);
24510923SEvan.Yan@Sun.COM #else
24610923SEvan.Yan@Sun.COM #define	DEBUG0(fmt)
24710923SEvan.Yan@Sun.COM #define	DEBUG1(fmt, a1)
24810923SEvan.Yan@Sun.COM #define	DEBUG2(fmt, a1, a2)
24910923SEvan.Yan@Sun.COM #define	DEBUG3(fmt, a1, a2, a3)
25010923SEvan.Yan@Sun.COM #define	DEBUG4(fmt, a1, a2, a3, a4)
25110923SEvan.Yan@Sun.COM #endif
25210923SEvan.Yan@Sun.COM 
25310923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
25410923SEvan.Yan@Sun.COM int pcicfg_dont_interpret = 0;
25510923SEvan.Yan@Sun.COM #else
25610923SEvan.Yan@Sun.COM int pcicfg_dont_interpret = 1;
25710923SEvan.Yan@Sun.COM #endif
25810923SEvan.Yan@Sun.COM 
25910923SEvan.Yan@Sun.COM /*
26010923SEvan.Yan@Sun.COM  * forward declarations for routines defined in this module (called here)
26110923SEvan.Yan@Sun.COM  */
26210923SEvan.Yan@Sun.COM 
26310923SEvan.Yan@Sun.COM static int pcicfg_add_config_reg(dev_info_t *,
26410923SEvan.Yan@Sun.COM     uint_t, uint_t, uint_t);
26510923SEvan.Yan@Sun.COM static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
26611245SZhijun.Fu@Sun.COM     uint_t *, pcicfg_flags_t, boolean_t);
26710923SEvan.Yan@Sun.COM 
26810923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
26910923SEvan.Yan@Sun.COM static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
27010923SEvan.Yan@Sun.COM 	uint16_t, uint16_t, uchar_t **, int *, int, int);
27110923SEvan.Yan@Sun.COM #endif
27210923SEvan.Yan@Sun.COM 
27310923SEvan.Yan@Sun.COM static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t,
27411245SZhijun.Fu@Sun.COM     uint_t *, pcicfg_flags_t, boolean_t);
27510923SEvan.Yan@Sun.COM static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
27611245SZhijun.Fu@Sun.COM     uint_t *, boolean_t);
27710923SEvan.Yan@Sun.COM static int pcicfg_free_all_resources(dev_info_t *);
27810923SEvan.Yan@Sun.COM static int pcicfg_alloc_new_resources(dev_info_t *);
27910923SEvan.Yan@Sun.COM static int pcicfg_match_dev(dev_info_t *, void *);
28010923SEvan.Yan@Sun.COM static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
28110923SEvan.Yan@Sun.COM static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
28210923SEvan.Yan@Sun.COM static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
28310923SEvan.Yan@Sun.COM static int pcicfg_destroy_phdl(dev_info_t *);
28410923SEvan.Yan@Sun.COM static int pcicfg_sum_resources(dev_info_t *, void *);
28510923SEvan.Yan@Sun.COM static int pcicfg_find_resource_end(dev_info_t *, void *);
28610923SEvan.Yan@Sun.COM static int pcicfg_allocate_chunk(dev_info_t *);
28710923SEvan.Yan@Sun.COM static int pcicfg_program_ap(dev_info_t *);
28810923SEvan.Yan@Sun.COM static int pcicfg_device_assign(dev_info_t *);
28910923SEvan.Yan@Sun.COM static int pcicfg_bridge_assign(dev_info_t *, void *);
29010923SEvan.Yan@Sun.COM static int pcicfg_device_assign_readonly(dev_info_t *);
29110923SEvan.Yan@Sun.COM static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
29210923SEvan.Yan@Sun.COM static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t,
29310923SEvan.Yan@Sun.COM     dev_info_t *);
29410923SEvan.Yan@Sun.COM static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
29510923SEvan.Yan@Sun.COM static void pcicfg_enable_bridge_probe_err(dev_info_t *dip,
29610923SEvan.Yan@Sun.COM 				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
29710923SEvan.Yan@Sun.COM static void pcicfg_disable_bridge_probe_err(dev_info_t *dip,
29810923SEvan.Yan@Sun.COM 				ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
29910923SEvan.Yan@Sun.COM static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
30010923SEvan.Yan@Sun.COM static void pcicfg_device_on(ddi_acc_handle_t);
30110923SEvan.Yan@Sun.COM static void pcicfg_device_off(ddi_acc_handle_t);
30210923SEvan.Yan@Sun.COM static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int);
30310923SEvan.Yan@Sun.COM static int pcicfg_free_bridge_resources(dev_info_t *);
30410923SEvan.Yan@Sun.COM static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t);
30511245SZhijun.Fu@Sun.COM static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
30610923SEvan.Yan@Sun.COM static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
30710923SEvan.Yan@Sun.COM static void pcicfg_config_teardown(ddi_acc_handle_t *);
30810923SEvan.Yan@Sun.COM static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
30910923SEvan.Yan@Sun.COM static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
31010923SEvan.Yan@Sun.COM static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *);
31110923SEvan.Yan@Sun.COM static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *,
31210923SEvan.Yan@Sun.COM     ddi_device_acc_attr_t *, ddi_acc_handle_t *);
31310923SEvan.Yan@Sun.COM static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
31410923SEvan.Yan@Sun.COM static int pcicfg_dump_assigned(dev_info_t *);
31510923SEvan.Yan@Sun.COM static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
31610923SEvan.Yan@Sun.COM static int pcicfg_indirect_map(dev_info_t *dip);
31710923SEvan.Yan@Sun.COM static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
31810923SEvan.Yan@Sun.COM 				uint64_t *, uint_t);
31910923SEvan.Yan@Sun.COM static int pcicfg_is_ntbridge(dev_info_t *);
32010923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
32110923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_configure_done(dev_info_t *);
32210923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_unconfigure(dev_info_t *);
32310923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
32410923SEvan.Yan@Sun.COM static void pcicfg_free_hole(hole_t *);
32510923SEvan.Yan@Sun.COM static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
32610923SEvan.Yan@Sun.COM static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *);
32710923SEvan.Yan@Sun.COM static int pcicfg_ari_configure(dev_info_t *);
32810923SEvan.Yan@Sun.COM static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
32910923SEvan.Yan@Sun.COM static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
33010923SEvan.Yan@Sun.COM static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
33110923SEvan.Yan@Sun.COM     uint32_t, uint32_t, uint_t);
33211245SZhijun.Fu@Sun.COM static boolean_t is_pcie_fabric(dev_info_t *dip);
33310923SEvan.Yan@Sun.COM 
33410923SEvan.Yan@Sun.COM #ifdef DEBUG
33510923SEvan.Yan@Sun.COM static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
33610923SEvan.Yan@Sun.COM static void pcicfg_dump_device_config(ddi_acc_handle_t);
33710923SEvan.Yan@Sun.COM 
33810923SEvan.Yan@Sun.COM static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
33910923SEvan.Yan@Sun.COM static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
34010923SEvan.Yan@Sun.COM 
34110923SEvan.Yan@Sun.COM #define	PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
34210923SEvan.Yan@Sun.COM #define	PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
34310923SEvan.Yan@Sun.COM #define	PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
34410923SEvan.Yan@Sun.COM #else
34510923SEvan.Yan@Sun.COM #define	PCICFG_DUMP_COMMON_CONFIG(handle)
34610923SEvan.Yan@Sun.COM #define	PCICFG_DUMP_DEVICE_CONFIG(handle)
34710923SEvan.Yan@Sun.COM #define	PCICFG_DUMP_BRIDGE_CONFIG(handle)
34810923SEvan.Yan@Sun.COM #endif
34910923SEvan.Yan@Sun.COM 
35010923SEvan.Yan@Sun.COM static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
35110923SEvan.Yan@Sun.COM static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
35210923SEvan.Yan@Sun.COM 
35310923SEvan.Yan@Sun.COM #ifndef _DONT_USE_1275_GENERIC_NAMES
35410923SEvan.Yan@Sun.COM /*
35510923SEvan.Yan@Sun.COM  * Class code table
35610923SEvan.Yan@Sun.COM  */
35710923SEvan.Yan@Sun.COM static struct pcicfg_name_entry pcicfg_class_lookup [] = {
35810923SEvan.Yan@Sun.COM 
35910923SEvan.Yan@Sun.COM 	{ 0x001, "display" },
36010923SEvan.Yan@Sun.COM 	{ 0x100, "scsi" },
36110923SEvan.Yan@Sun.COM 	{ 0x101, "ide" },
36210923SEvan.Yan@Sun.COM 	{ 0x102, "fdc" },
36310923SEvan.Yan@Sun.COM 	{ 0x103, "ipi" },
36410923SEvan.Yan@Sun.COM 	{ 0x104, "raid" },
36510923SEvan.Yan@Sun.COM 	{ 0x200, "ethernet" },
36610923SEvan.Yan@Sun.COM 	{ 0x201, "token-ring" },
36710923SEvan.Yan@Sun.COM 	{ 0x202, "fddi" },
36810923SEvan.Yan@Sun.COM 	{ 0x203, "atm" },
36910923SEvan.Yan@Sun.COM 	{ 0x300, "display" },
37010923SEvan.Yan@Sun.COM 	{ 0x400, "video" },
37110923SEvan.Yan@Sun.COM 	{ 0x401, "sound" },
37210923SEvan.Yan@Sun.COM 	{ 0x500, "memory" },
37310923SEvan.Yan@Sun.COM 	{ 0x501, "flash" },
37410923SEvan.Yan@Sun.COM 	{ 0x600, "host" },
37510923SEvan.Yan@Sun.COM 	{ 0x601, "isa" },
37610923SEvan.Yan@Sun.COM 	{ 0x602, "eisa" },
37710923SEvan.Yan@Sun.COM 	{ 0x603, "mca" },
37810923SEvan.Yan@Sun.COM 	{ 0x604, "pci" },
37910923SEvan.Yan@Sun.COM 	{ 0x605, "pcmcia" },
38010923SEvan.Yan@Sun.COM 	{ 0x606, "nubus" },
38110923SEvan.Yan@Sun.COM 	{ 0x607, "cardbus" },
38210923SEvan.Yan@Sun.COM 	{ 0x609, "pci" },
38310923SEvan.Yan@Sun.COM 	{ 0x700, "serial" },
38410923SEvan.Yan@Sun.COM 	{ 0x701, "parallel" },
38510923SEvan.Yan@Sun.COM 	{ 0x800, "interrupt-controller" },
38610923SEvan.Yan@Sun.COM 	{ 0x801, "dma-controller" },
38710923SEvan.Yan@Sun.COM 	{ 0x802, "timer" },
38810923SEvan.Yan@Sun.COM 	{ 0x803, "rtc" },
38910923SEvan.Yan@Sun.COM 	{ 0x900, "keyboard" },
39010923SEvan.Yan@Sun.COM 	{ 0x901, "pen" },
39110923SEvan.Yan@Sun.COM 	{ 0x902, "mouse" },
39210923SEvan.Yan@Sun.COM 	{ 0xa00, "dock" },
39310923SEvan.Yan@Sun.COM 	{ 0xb00, "cpu" },
39410923SEvan.Yan@Sun.COM 	{ 0xc00, "firewire" },
39510923SEvan.Yan@Sun.COM 	{ 0xc01, "access-bus" },
39610923SEvan.Yan@Sun.COM 	{ 0xc02, "ssa" },
39710923SEvan.Yan@Sun.COM 	{ 0xc03, "usb" },
39810923SEvan.Yan@Sun.COM 	{ 0xc04, "fibre-channel" },
39910923SEvan.Yan@Sun.COM 	{ 0, 0 }
40010923SEvan.Yan@Sun.COM };
40110923SEvan.Yan@Sun.COM #endif /* _DONT_USE_1275_GENERIC_NAMES */
40210923SEvan.Yan@Sun.COM 
40310923SEvan.Yan@Sun.COM /*
40410923SEvan.Yan@Sun.COM  * Module control operations
40510923SEvan.Yan@Sun.COM  */
40610923SEvan.Yan@Sun.COM 
40710923SEvan.Yan@Sun.COM extern struct mod_ops mod_miscops;
40810923SEvan.Yan@Sun.COM 
40910923SEvan.Yan@Sun.COM static struct modlmisc modlmisc = {
41010923SEvan.Yan@Sun.COM 	&mod_miscops, /* Type of module */
41110923SEvan.Yan@Sun.COM 	"PCIe/PCI Config (EFCode Enabled)"
41210923SEvan.Yan@Sun.COM };
41310923SEvan.Yan@Sun.COM 
41410923SEvan.Yan@Sun.COM static struct modlinkage modlinkage = {
41510923SEvan.Yan@Sun.COM 	MODREV_1, (void *)&modlmisc, NULL
41610923SEvan.Yan@Sun.COM };
41710923SEvan.Yan@Sun.COM 
41810923SEvan.Yan@Sun.COM #ifdef DEBUG
41910923SEvan.Yan@Sun.COM 
42010923SEvan.Yan@Sun.COM static void
pcicfg_dump_common_config(ddi_acc_handle_t config_handle)42110923SEvan.Yan@Sun.COM pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
42210923SEvan.Yan@Sun.COM {
42310923SEvan.Yan@Sun.COM 	if ((pcicfg_debug & 1) == 0)
42410923SEvan.Yan@Sun.COM 		return;
42510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Vendor ID   = [0x%x]\n",
42610923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_VENID));
42710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
42810923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
42910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Command REG = [0x%x]\n",
43010923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_COMM));
43110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Status  REG = [0x%x]\n",
43210923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_STAT));
43310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Revision ID = [0x%x]\n",
43410923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_REVID));
43510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Prog Class  = [0x%x]\n",
43610923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
43710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Dev Class   = [0x%x]\n",
43810923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
43910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Base Class  = [0x%x]\n",
44010923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_BASCLASS));
44110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Device ID   = [0x%x]\n",
44210923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
44310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Header Type = [0x%x]\n",
44410923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_HEADER));
44510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " BIST        = [0x%x]\n",
44610923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_BIST));
44710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " BASE 0      = [0x%x]\n",
44810923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_BASE0));
44910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " BASE 1      = [0x%x]\n",
45010923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_BASE1));
45110923SEvan.Yan@Sun.COM 
45210923SEvan.Yan@Sun.COM }
45310923SEvan.Yan@Sun.COM 
45410923SEvan.Yan@Sun.COM static void
pcicfg_dump_device_config(ddi_acc_handle_t config_handle)45510923SEvan.Yan@Sun.COM pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
45610923SEvan.Yan@Sun.COM {
45710923SEvan.Yan@Sun.COM 	if ((pcicfg_debug & 1) == 0)
45810923SEvan.Yan@Sun.COM 		return;
45910923SEvan.Yan@Sun.COM 	pcicfg_dump_common_config(config_handle);
46010923SEvan.Yan@Sun.COM 
46110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " BASE 2      = [0x%x]\n",
46210923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_BASE2));
46310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " BASE 3      = [0x%x]\n",
46410923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_BASE3));
46510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " BASE 4      = [0x%x]\n",
46610923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_BASE4));
46710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " BASE 5      = [0x%x]\n",
46810923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_BASE5));
46910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n",
47010923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_CIS));
47110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Sub VID     = [0x%x]\n",
47210923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_SUBVENID));
47310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Sub SID     = [0x%x]\n",
47410923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
47510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " ROM         = [0x%x]\n",
47610923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_CONF_ROM));
47710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " I Line      = [0x%x]\n",
47810923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_ILINE));
47910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " I Pin       = [0x%x]\n",
48010923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_IPIN));
48110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Max Grant   = [0x%x]\n",
48210923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_MIN_G));
48310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Max Latent  = [0x%x]\n",
48410923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_CONF_MAX_L));
48510923SEvan.Yan@Sun.COM }
48610923SEvan.Yan@Sun.COM 
48710923SEvan.Yan@Sun.COM static void
pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)48810923SEvan.Yan@Sun.COM pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
48910923SEvan.Yan@Sun.COM {
49010923SEvan.Yan@Sun.COM 	if ((pcicfg_debug & 1) == 0)
49110923SEvan.Yan@Sun.COM 		return;
49210923SEvan.Yan@Sun.COM 
49310923SEvan.Yan@Sun.COM 	pcicfg_dump_common_config(config_handle);
49410923SEvan.Yan@Sun.COM 
49510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, "........................................\n");
49610923SEvan.Yan@Sun.COM 
49710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Pri Bus     = [0x%x]\n",
49810923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
49910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Sec Bus     = [0x%x]\n",
50010923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_SECBUS));
50110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Sub Bus     = [0x%x]\n",
50210923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
50310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Latency     = [0x%x]\n",
50410923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
50510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n",
50610923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
50710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " I/O Lim LO  = [0x%x]\n",
50810923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
50910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Sec. Status = [0x%x]\n",
51010923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
51110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Mem Base    = [0x%x]\n",
51210923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
51310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Mem Limit   = [0x%x]\n",
51410923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
51510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n",
51610923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
51710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " PF Mem Lim  = [0x%x]\n",
51810923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
51910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " PF Base HI  = [0x%x]\n",
52010923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
52110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " PF Lim  HI  = [0x%x]\n",
52210923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
52310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n",
52410923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
52510923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " I/O Lim HI  = [0x%x]\n",
52610923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
52710923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " ROM addr    = [0x%x]\n",
52810923SEvan.Yan@Sun.COM 	    pci_config_get32(config_handle, PCI_BCNF_ROM));
52910923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Intr Line   = [0x%x]\n",
53010923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_ILINE));
53110923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Intr Pin    = [0x%x]\n",
53210923SEvan.Yan@Sun.COM 	    pci_config_get8(config_handle, PCI_BCNF_IPIN));
53310923SEvan.Yan@Sun.COM 	cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n",
53410923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
53510923SEvan.Yan@Sun.COM }
53610923SEvan.Yan@Sun.COM 
53710923SEvan.Yan@Sun.COM #endif
53810923SEvan.Yan@Sun.COM 
53910923SEvan.Yan@Sun.COM 
54010923SEvan.Yan@Sun.COM int
_init()54110923SEvan.Yan@Sun.COM _init()
54210923SEvan.Yan@Sun.COM {
54310923SEvan.Yan@Sun.COM 	DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n");
54410923SEvan.Yan@Sun.COM 
54510923SEvan.Yan@Sun.COM 	mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
54610923SEvan.Yan@Sun.COM 	return (mod_install(&modlinkage));
54710923SEvan.Yan@Sun.COM }
54810923SEvan.Yan@Sun.COM 
54910923SEvan.Yan@Sun.COM int
_fini(void)55010923SEvan.Yan@Sun.COM _fini(void)
55110923SEvan.Yan@Sun.COM {
55210923SEvan.Yan@Sun.COM 	int error;
55310923SEvan.Yan@Sun.COM 
55410923SEvan.Yan@Sun.COM 	error = mod_remove(&modlinkage);
55510923SEvan.Yan@Sun.COM 	if (error != 0) {
55610923SEvan.Yan@Sun.COM 		return (error);
55710923SEvan.Yan@Sun.COM 	}
55810923SEvan.Yan@Sun.COM 	mutex_destroy(&pcicfg_list_mutex);
55910923SEvan.Yan@Sun.COM 	return (0);
56010923SEvan.Yan@Sun.COM }
56110923SEvan.Yan@Sun.COM 
56210923SEvan.Yan@Sun.COM int
_info(modinfop)56310923SEvan.Yan@Sun.COM _info(modinfop)
56410923SEvan.Yan@Sun.COM struct modinfo *modinfop;
56510923SEvan.Yan@Sun.COM {
56610923SEvan.Yan@Sun.COM 	return (mod_info(&modlinkage, modinfop));
56710923SEvan.Yan@Sun.COM }
56810923SEvan.Yan@Sun.COM 
56910923SEvan.Yan@Sun.COM /*ARGSUSED*/
57010923SEvan.Yan@Sun.COM static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)57110923SEvan.Yan@Sun.COM pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
57210923SEvan.Yan@Sun.COM {
57310923SEvan.Yan@Sun.COM 	uint8_t num_slots = 0;
57410923SEvan.Yan@Sun.COM 	uint16_t cap_ptr;
57510923SEvan.Yan@Sun.COM 
57610923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG,
57710923SEvan.Yan@Sun.COM 	    &cap_ptr)) == DDI_SUCCESS) {
57810923SEvan.Yan@Sun.COM 		uint32_t config;
57910923SEvan.Yan@Sun.COM 
58010923SEvan.Yan@Sun.COM 		PCI_CAP_PUT8(handle, NULL, cap_ptr, PCI_HP_DWORD_SELECT_OFF,
58110923SEvan.Yan@Sun.COM 		    PCI_HP_SLOT_CONFIGURATION_REG);
58210923SEvan.Yan@Sun.COM 		config = PCI_CAP_GET32(handle, NULL, cap_ptr,
58310923SEvan.Yan@Sun.COM 		    PCI_HP_DWORD_DATA_OFF);
58410923SEvan.Yan@Sun.COM 		num_slots = config & 0x1F;
58510923SEvan.Yan@Sun.COM 	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr))
58610923SEvan.Yan@Sun.COM 	    == DDI_SUCCESS) {
58710923SEvan.Yan@Sun.COM 		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL,
58810923SEvan.Yan@Sun.COM 		    cap_ptr, PCI_CAP_ID_REGS_OFF);
58910923SEvan.Yan@Sun.COM 
59010923SEvan.Yan@Sun.COM 		num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
59110923SEvan.Yan@Sun.COM 	} else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
59210923SEvan.Yan@Sun.COM 	    == DDI_SUCCESS) {
59310923SEvan.Yan@Sun.COM 		int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr,
59410923SEvan.Yan@Sun.COM 		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
59510923SEvan.Yan@Sun.COM 
59610923SEvan.Yan@Sun.COM 		if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) &&
59710923SEvan.Yan@Sun.COM 		    (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP)
59810923SEvan.Yan@Sun.COM 		    & PCIE_PCIECAP_SLOT_IMPL))
59910923SEvan.Yan@Sun.COM 				num_slots = 1;
60010923SEvan.Yan@Sun.COM 	}
60110923SEvan.Yan@Sun.COM 
60210923SEvan.Yan@Sun.COM 	DEBUG3("%s#%d has %d slots",
60310923SEvan.Yan@Sun.COM 	    ddi_get_name(dip), ddi_get_instance(dip), num_slots);
60410923SEvan.Yan@Sun.COM 
60510923SEvan.Yan@Sun.COM 	return (num_slots);
60610923SEvan.Yan@Sun.COM }
60710923SEvan.Yan@Sun.COM 
60810923SEvan.Yan@Sun.COM /*ARGSUSED*/
60910923SEvan.Yan@Sun.COM static uint8_t
pcicfg_is_chassis(dev_info_t * dip,ddi_acc_handle_t handle)61010923SEvan.Yan@Sun.COM pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle)
61110923SEvan.Yan@Sun.COM {
61210923SEvan.Yan@Sun.COM 	uint16_t cap_ptr;
61310923SEvan.Yan@Sun.COM 
61410923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) !=
61510923SEvan.Yan@Sun.COM 	    DDI_FAILURE) {
61610923SEvan.Yan@Sun.COM 
61710923SEvan.Yan@Sun.COM 		uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2);
61810923SEvan.Yan@Sun.COM 		if (PCI_CAPSLOT_FIC(esr_reg))
61910923SEvan.Yan@Sun.COM 			return (B_TRUE);
62010923SEvan.Yan@Sun.COM 	}
62110923SEvan.Yan@Sun.COM 	return (B_FALSE);
62210923SEvan.Yan@Sun.COM }
62310923SEvan.Yan@Sun.COM 
62410923SEvan.Yan@Sun.COM /*ARGSUSED*/
62510923SEvan.Yan@Sun.COM static int
pcicfg_pcie_dev(dev_info_t * dip,int bus_type,pcicfg_err_regs_t * regs)62610923SEvan.Yan@Sun.COM pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs)
62710923SEvan.Yan@Sun.COM {
62810923SEvan.Yan@Sun.COM 	/* get parent device's device_type property */
62910923SEvan.Yan@Sun.COM 	char *device_type;
63010923SEvan.Yan@Sun.COM 	int rc = DDI_FAILURE;
63110923SEvan.Yan@Sun.COM 	dev_info_t *pdip = ddi_get_parent(dip);
63210923SEvan.Yan@Sun.COM 
63310923SEvan.Yan@Sun.COM 	regs->pcie_dev = 0;
63410923SEvan.Yan@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
63510923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "device_type", &device_type)
63610923SEvan.Yan@Sun.COM 	    != DDI_PROP_SUCCESS) {
63710923SEvan.Yan@Sun.COM 		DEBUG2("device_type property missing for %s#%d",
63810923SEvan.Yan@Sun.COM 		    ddi_get_name(pdip), ddi_get_instance(pdip));
63910923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
64010923SEvan.Yan@Sun.COM 	}
64110923SEvan.Yan@Sun.COM 	switch (bus_type) {
64210923SEvan.Yan@Sun.COM 		case PCICFG_DEVICE_TYPE_PCIE:
64310923SEvan.Yan@Sun.COM 			if (strcmp(device_type, "pciex") == 0) {
64410923SEvan.Yan@Sun.COM 				rc = DDI_SUCCESS;
64510923SEvan.Yan@Sun.COM 				regs->pcie_dev = 1;
64610923SEvan.Yan@Sun.COM 			}
64710923SEvan.Yan@Sun.COM 			break;
64810923SEvan.Yan@Sun.COM 		case PCICFG_DEVICE_TYPE_PCI:
64910923SEvan.Yan@Sun.COM 			if (strcmp(device_type, "pci") == 0)
65010923SEvan.Yan@Sun.COM 				rc = DDI_SUCCESS;
65110923SEvan.Yan@Sun.COM 			break;
65210923SEvan.Yan@Sun.COM 		default:
65310923SEvan.Yan@Sun.COM 			break;
65410923SEvan.Yan@Sun.COM 	}
65510923SEvan.Yan@Sun.COM 	ddi_prop_free(device_type);
65610923SEvan.Yan@Sun.COM 	return (rc);
65710923SEvan.Yan@Sun.COM }
65810923SEvan.Yan@Sun.COM 
65910923SEvan.Yan@Sun.COM /*ARGSUSED*/
66010923SEvan.Yan@Sun.COM static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)66110923SEvan.Yan@Sun.COM pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
66210923SEvan.Yan@Sun.COM {
66310923SEvan.Yan@Sun.COM 	int port_type = -1;
66410923SEvan.Yan@Sun.COM 	uint16_t cap_ptr;
66510923SEvan.Yan@Sun.COM 
66610923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
66710923SEvan.Yan@Sun.COM 	    DDI_FAILURE)
66810923SEvan.Yan@Sun.COM 		port_type = PCI_CAP_GET16(handle, NULL,
66910923SEvan.Yan@Sun.COM 		    cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
67010923SEvan.Yan@Sun.COM 
67110923SEvan.Yan@Sun.COM 	return (port_type);
67210923SEvan.Yan@Sun.COM }
67310923SEvan.Yan@Sun.COM 
67410923SEvan.Yan@Sun.COM static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)67510923SEvan.Yan@Sun.COM pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
67610923SEvan.Yan@Sun.COM {
67710923SEvan.Yan@Sun.COM 	int port_type = pcicfg_pcie_port_type(dip, handle);
67810923SEvan.Yan@Sun.COM 
67910923SEvan.Yan@Sun.COM 	DEBUG1("device port_type = %x\n", port_type);
68010923SEvan.Yan@Sun.COM 	/* No PCIe CAP regs, we are not PCIe device_type */
68110923SEvan.Yan@Sun.COM 	if (port_type < 0)
68210923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
68310923SEvan.Yan@Sun.COM 
68410923SEvan.Yan@Sun.COM 	/* check for all PCIe device_types */
68510923SEvan.Yan@Sun.COM 	if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
68610923SEvan.Yan@Sun.COM 	    (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
68710923SEvan.Yan@Sun.COM 	    (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
68810923SEvan.Yan@Sun.COM 	    (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
68910923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
69010923SEvan.Yan@Sun.COM 
69110923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
69210923SEvan.Yan@Sun.COM 
69310923SEvan.Yan@Sun.COM }
69410923SEvan.Yan@Sun.COM 
69510923SEvan.Yan@Sun.COM /*
69610923SEvan.Yan@Sun.COM  * In the following functions ndi_devi_enter() without holding the
69710923SEvan.Yan@Sun.COM  * parent dip is sufficient. This is because  pci dr is driven through
69810923SEvan.Yan@Sun.COM  * opens on the nexus which is in the device tree path above the node
69910923SEvan.Yan@Sun.COM  * being operated on, and implicitly held due to the open.
70010923SEvan.Yan@Sun.COM  */
70110923SEvan.Yan@Sun.COM 
70210923SEvan.Yan@Sun.COM /*
70310923SEvan.Yan@Sun.COM  * This entry point is called to configure a device (and
70410923SEvan.Yan@Sun.COM  * all its children) on the given bus. It is called when
70510923SEvan.Yan@Sun.COM  * a new device is added to the PCI domain.  This routine
70610923SEvan.Yan@Sun.COM  * will create the device tree and program the devices
70710923SEvan.Yan@Sun.COM  * registers.
70810923SEvan.Yan@Sun.COM  */
70910923SEvan.Yan@Sun.COM 
71010923SEvan.Yan@Sun.COM int
pcicfg_configure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)71110923SEvan.Yan@Sun.COM pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
71210923SEvan.Yan@Sun.COM     pcicfg_flags_t flags)
71310923SEvan.Yan@Sun.COM {
71410923SEvan.Yan@Sun.COM 	uint_t bus;
71510923SEvan.Yan@Sun.COM 	int len;
71610923SEvan.Yan@Sun.COM 	int func;
71710923SEvan.Yan@Sun.COM 	int trans_device;
71810923SEvan.Yan@Sun.COM 	dev_info_t *new_device;
71910923SEvan.Yan@Sun.COM 	pcicfg_bus_range_t pci_bus_range;
72010923SEvan.Yan@Sun.COM 	int rv;
72110923SEvan.Yan@Sun.COM 	int circ;
72210923SEvan.Yan@Sun.COM 	uint_t highest_bus = 0;
72310923SEvan.Yan@Sun.COM 	int ari_mode = B_FALSE;
72410923SEvan.Yan@Sun.COM 	int max_function = PCICFG_MAX_FUNCTION;
72511245SZhijun.Fu@Sun.COM 	boolean_t is_pcie;
72610923SEvan.Yan@Sun.COM 
72710923SEvan.Yan@Sun.COM 	if (flags == PCICFG_FLAG_ENABLE_ARI)
72810923SEvan.Yan@Sun.COM 		return (pcicfg_ari_configure(devi));
72910923SEvan.Yan@Sun.COM 
73010923SEvan.Yan@Sun.COM 	/*
73110923SEvan.Yan@Sun.COM 	 * Start probing at the device specified in "device" on the
73210923SEvan.Yan@Sun.COM 	 * "bus" specified.
73310923SEvan.Yan@Sun.COM 	 */
73410923SEvan.Yan@Sun.COM 	len = sizeof (pcicfg_bus_range_t);
73510923SEvan.Yan@Sun.COM 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
73610923SEvan.Yan@Sun.COM 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
73710923SEvan.Yan@Sun.COM 		DEBUG0("no bus-range property\n");
73810923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
73910923SEvan.Yan@Sun.COM 	}
74010923SEvan.Yan@Sun.COM 
74110923SEvan.Yan@Sun.COM 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
74210923SEvan.Yan@Sun.COM 
74311245SZhijun.Fu@Sun.COM 	is_pcie = is_pcie_fabric(devi);
74411245SZhijun.Fu@Sun.COM 
74510923SEvan.Yan@Sun.COM 	ndi_devi_enter(devi, &circ);
74610923SEvan.Yan@Sun.COM 	for (func = 0; func < max_function; ) {
74710923SEvan.Yan@Sun.COM 		if ((function != PCICFG_ALL_FUNC) && (function != func))
74810923SEvan.Yan@Sun.COM 			goto next;
74910923SEvan.Yan@Sun.COM 
75010923SEvan.Yan@Sun.COM 		if (ari_mode)
75110923SEvan.Yan@Sun.COM 			trans_device = func >> 3;
75210923SEvan.Yan@Sun.COM 		else
75310923SEvan.Yan@Sun.COM 			trans_device = device;
75410923SEvan.Yan@Sun.COM 
75510923SEvan.Yan@Sun.COM 		DEBUG3("Configuring [0x%x][0x%x][0x%x]\n",
75610923SEvan.Yan@Sun.COM 		    bus, trans_device, func & 7);
75710923SEvan.Yan@Sun.COM 
75810923SEvan.Yan@Sun.COM 		/*
75910923SEvan.Yan@Sun.COM 		 * Try executing fcode if available.
76010923SEvan.Yan@Sun.COM 		 */
76110923SEvan.Yan@Sun.COM 		switch (rv = pcicfg_fcode_probe(devi, bus, trans_device,
76211245SZhijun.Fu@Sun.COM 		    func & 7, &highest_bus, flags, is_pcie)) {
76310923SEvan.Yan@Sun.COM 			case PCICFG_FAILURE:
76410923SEvan.Yan@Sun.COM 				DEBUG2("configure failed: "
76510923SEvan.Yan@Sun.COM 				    "bus [0x%x] device [0x%x]\n",
76610923SEvan.Yan@Sun.COM 				    bus, trans_device);
76710923SEvan.Yan@Sun.COM 				break;
76810923SEvan.Yan@Sun.COM 			case PCICFG_NODEVICE:
76910923SEvan.Yan@Sun.COM 				DEBUG3("no device : bus "
77010923SEvan.Yan@Sun.COM 				    "[0x%x] slot [0x%x] func [0x%x]\n",
77110923SEvan.Yan@Sun.COM 				    bus, trans_device, func & 7);
77212622SAlan.Adamson@Sun.COM 
77312622SAlan.Adamson@Sun.COM 				/*
77412622SAlan.Adamson@Sun.COM 				 * When walking the list of ARI functions
77512622SAlan.Adamson@Sun.COM 				 * we don't expect to see a non-present
77612622SAlan.Adamson@Sun.COM 				 * function, so we will stop walking
77712622SAlan.Adamson@Sun.COM 				 * the function list.
77812622SAlan.Adamson@Sun.COM 				 */
77912622SAlan.Adamson@Sun.COM 				if (ari_mode == B_TRUE)
78012622SAlan.Adamson@Sun.COM 					break;
78112622SAlan.Adamson@Sun.COM 
78210923SEvan.Yan@Sun.COM 				if (func)
78310923SEvan.Yan@Sun.COM 					goto next;
78410923SEvan.Yan@Sun.COM 				break;
78510923SEvan.Yan@Sun.COM 			default:
78610923SEvan.Yan@Sun.COM 				DEBUG3("configure: bus => [%d] "
78710923SEvan.Yan@Sun.COM 				    "slot => [%d] func => [%d]\n",
78810923SEvan.Yan@Sun.COM 				    bus, trans_device, func & 7);
78910923SEvan.Yan@Sun.COM 				break;
79010923SEvan.Yan@Sun.COM 		}
79110923SEvan.Yan@Sun.COM 
79210923SEvan.Yan@Sun.COM 		if (rv != PCICFG_SUCCESS)
79310923SEvan.Yan@Sun.COM 			break;
79410923SEvan.Yan@Sun.COM 
79510923SEvan.Yan@Sun.COM 		if ((new_device = pcicfg_devi_find(devi,
79610923SEvan.Yan@Sun.COM 		    trans_device, (func & 7))) == NULL) {
79710923SEvan.Yan@Sun.COM 			DEBUG0("Did'nt find device node just created\n");
79810923SEvan.Yan@Sun.COM 			goto cleanup;
79910923SEvan.Yan@Sun.COM 		}
80010923SEvan.Yan@Sun.COM 
80110923SEvan.Yan@Sun.COM next:
80210923SEvan.Yan@Sun.COM 		/*
80310923SEvan.Yan@Sun.COM 		 * Determine if ARI Forwarding should be enabled.
80410923SEvan.Yan@Sun.COM 		 */
80510923SEvan.Yan@Sun.COM 		if (func == 0) {
80610923SEvan.Yan@Sun.COM 			if ((pcie_ari_supported(devi)
80710923SEvan.Yan@Sun.COM 			    == PCIE_ARI_FORW_SUPPORTED) &&
80810923SEvan.Yan@Sun.COM 			    (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
80910923SEvan.Yan@Sun.COM 				if (pcie_ari_enable(devi) == DDI_SUCCESS) {
81010923SEvan.Yan@Sun.COM 					(void) ddi_prop_create(DDI_DEV_T_NONE,
81110923SEvan.Yan@Sun.COM 					    devi,  DDI_PROP_CANSLEEP,
81210923SEvan.Yan@Sun.COM 					    "ari-enabled", NULL, 0);
81310923SEvan.Yan@Sun.COM 
81410923SEvan.Yan@Sun.COM 					ari_mode = B_TRUE;
81510923SEvan.Yan@Sun.COM 					max_function = PCICFG_MAX_ARI_FUNCTION;
81610923SEvan.Yan@Sun.COM 				}
81710923SEvan.Yan@Sun.COM 			}
81810923SEvan.Yan@Sun.COM 		}
81910923SEvan.Yan@Sun.COM 
82010923SEvan.Yan@Sun.COM 		if (ari_mode == B_TRUE) {
82110923SEvan.Yan@Sun.COM 			int next_function;
82210923SEvan.Yan@Sun.COM 
82310923SEvan.Yan@Sun.COM 			DEBUG0("Next Function - ARI Device\n");
82410923SEvan.Yan@Sun.COM 			if (pcie_ari_get_next_function(new_device,
82510923SEvan.Yan@Sun.COM 			    &next_function) != DDI_SUCCESS)
82610923SEvan.Yan@Sun.COM 				goto cleanup;
82710923SEvan.Yan@Sun.COM 
82810923SEvan.Yan@Sun.COM 			/*
82910923SEvan.Yan@Sun.COM 			 * Check if there are more fucntions to probe.
83010923SEvan.Yan@Sun.COM 			 */
83110923SEvan.Yan@Sun.COM 			if (next_function == 0) {
83210923SEvan.Yan@Sun.COM 				DEBUG0("Next Function - "
83310923SEvan.Yan@Sun.COM 				    "No more ARI Functions\n");
83410923SEvan.Yan@Sun.COM 				break;
83510923SEvan.Yan@Sun.COM 			}
83610923SEvan.Yan@Sun.COM 			func = next_function;
83710923SEvan.Yan@Sun.COM 		} else {
83810923SEvan.Yan@Sun.COM 			func++;
83910923SEvan.Yan@Sun.COM 		}
84010923SEvan.Yan@Sun.COM 
84110923SEvan.Yan@Sun.COM 		DEBUG1("Next Function - %x\n", func);
84210923SEvan.Yan@Sun.COM 	}
84310923SEvan.Yan@Sun.COM 
84410923SEvan.Yan@Sun.COM 	ndi_devi_exit(devi, circ);
84510923SEvan.Yan@Sun.COM 
84610923SEvan.Yan@Sun.COM 	if (func == 0)
84710923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);	/* probe failed */
84810923SEvan.Yan@Sun.COM 	else
84910923SEvan.Yan@Sun.COM 		return (PCICFG_SUCCESS);
85010923SEvan.Yan@Sun.COM 
85110923SEvan.Yan@Sun.COM cleanup:
85210923SEvan.Yan@Sun.COM 	/*
85310923SEvan.Yan@Sun.COM 	 * Clean up a partially created "probe state" tree.
85410923SEvan.Yan@Sun.COM 	 * There are no resources allocated to the in the
85510923SEvan.Yan@Sun.COM 	 * probe state.
85610923SEvan.Yan@Sun.COM 	 */
85710923SEvan.Yan@Sun.COM 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
85810923SEvan.Yan@Sun.COM 		max_function = PCICFG_MAX_ARI_FUNCTION;
85910923SEvan.Yan@Sun.COM 	else
86010923SEvan.Yan@Sun.COM 		max_function = PCICFG_MAX_FUNCTION;
86110923SEvan.Yan@Sun.COM 
86210923SEvan.Yan@Sun.COM 	for (func = 0; func < max_function; func++) {
86310923SEvan.Yan@Sun.COM 
86410923SEvan.Yan@Sun.COM 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
86510923SEvan.Yan@Sun.COM 			trans_device = func >> 3; /* ARI Device */
86610923SEvan.Yan@Sun.COM 		else
86710923SEvan.Yan@Sun.COM 			trans_device = device;
86810923SEvan.Yan@Sun.COM 
86910923SEvan.Yan@Sun.COM 		if ((new_device = pcicfg_devi_find(devi,
87010923SEvan.Yan@Sun.COM 		    trans_device, (func & 0x7))) == NULL) {
87110923SEvan.Yan@Sun.COM 			DEBUG0("No more devices to clean up\n");
87210923SEvan.Yan@Sun.COM 			continue;
87310923SEvan.Yan@Sun.COM 		}
87410923SEvan.Yan@Sun.COM 
87510923SEvan.Yan@Sun.COM 		DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
87610923SEvan.Yan@Sun.COM 		    trans_device, func & 7);
87710923SEvan.Yan@Sun.COM 		/*
87810923SEvan.Yan@Sun.COM 		 * If this was a bridge device it will have a
87910923SEvan.Yan@Sun.COM 		 * probe handle - if not, no harm in calling this.
88010923SEvan.Yan@Sun.COM 		 */
88110923SEvan.Yan@Sun.COM 		(void) pcicfg_destroy_phdl(new_device);
88211245SZhijun.Fu@Sun.COM 
88311245SZhijun.Fu@Sun.COM 		if (is_pcie) {
88411245SZhijun.Fu@Sun.COM 			/*
88511245SZhijun.Fu@Sun.COM 			 * Free bus_t structure
88611245SZhijun.Fu@Sun.COM 			 */
88711245SZhijun.Fu@Sun.COM 			if (ddi_get_child(new_device) != NULL)
88811245SZhijun.Fu@Sun.COM 				pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
88911245SZhijun.Fu@Sun.COM 
89011245SZhijun.Fu@Sun.COM 			pcie_fini_bus(new_device, PCIE_BUS_ALL);
89111245SZhijun.Fu@Sun.COM 		}
89210923SEvan.Yan@Sun.COM 		/*
89310923SEvan.Yan@Sun.COM 		 * This will free up the node
89410923SEvan.Yan@Sun.COM 		 */
89510923SEvan.Yan@Sun.COM 		(void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
89610923SEvan.Yan@Sun.COM 	}
89710923SEvan.Yan@Sun.COM 	ndi_devi_exit(devi, circ);
89810923SEvan.Yan@Sun.COM 
89910923SEvan.Yan@Sun.COM 	return (PCICFG_FAILURE);
90010923SEvan.Yan@Sun.COM }
90110923SEvan.Yan@Sun.COM 
90210923SEvan.Yan@Sun.COM /*
90310923SEvan.Yan@Sun.COM  * configure the child nodes of ntbridge. new_device points to ntbridge itself
90410923SEvan.Yan@Sun.COM  */
90510923SEvan.Yan@Sun.COM /*ARGSUSED*/
90610923SEvan.Yan@Sun.COM static uint_t
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)90710923SEvan.Yan@Sun.COM pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
90810923SEvan.Yan@Sun.COM {
90910923SEvan.Yan@Sun.COM 	int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
91010923SEvan.Yan@Sun.COM 	int			devno;
91110923SEvan.Yan@Sun.COM 	dev_info_t		*new_ntbridgechild;
91210923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	config_handle;
91310923SEvan.Yan@Sun.COM 	uint16_t		vid;
91410923SEvan.Yan@Sun.COM 	uint64_t		next_bus;
91510923SEvan.Yan@Sun.COM 	uint64_t		blen;
91610923SEvan.Yan@Sun.COM 	ndi_ra_request_t	req;
91710923SEvan.Yan@Sun.COM 	uint8_t			pcie_device_type = 0;
91810923SEvan.Yan@Sun.COM 
91910923SEvan.Yan@Sun.COM 	/*
92010923SEvan.Yan@Sun.COM 	 * If we need to do indirect config, lets create a property here
92110923SEvan.Yan@Sun.COM 	 * to let the child conf map routine know that it has to
92210923SEvan.Yan@Sun.COM 	 * go through the DDI calls, and not assume the devices are
92310923SEvan.Yan@Sun.COM 	 * mapped directly under the host.
92410923SEvan.Yan@Sun.COM 	 */
92510923SEvan.Yan@Sun.COM 	if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
92610923SEvan.Yan@Sun.COM 	    PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
92710923SEvan.Yan@Sun.COM 	    != DDI_SUCCESS) {
92810923SEvan.Yan@Sun.COM 
92910923SEvan.Yan@Sun.COM 		DEBUG0("Cannot create indirect conf map property.\n");
93010923SEvan.Yan@Sun.COM 		return ((uint_t)PCICFG_FAILURE);
93110923SEvan.Yan@Sun.COM 	}
93210923SEvan.Yan@Sun.COM 	if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
93310923SEvan.Yan@Sun.COM 		return ((uint_t)PCICFG_FAILURE);
93410923SEvan.Yan@Sun.COM 	/* check if we are PCIe device */
93510923SEvan.Yan@Sun.COM 	if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS)
93610923SEvan.Yan@Sun.COM 		pcie_device_type = 1;
93710923SEvan.Yan@Sun.COM 	pci_config_teardown(&config_handle);
93810923SEvan.Yan@Sun.COM 
93910923SEvan.Yan@Sun.COM 	/* create Bus node properties for ntbridge. */
94010923SEvan.Yan@Sun.COM 	if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) !=
94110923SEvan.Yan@Sun.COM 	    PCICFG_SUCCESS) {
94210923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set busnode props\n");
94310923SEvan.Yan@Sun.COM 		return (rc);
94410923SEvan.Yan@Sun.COM 	}
94510923SEvan.Yan@Sun.COM 
94610923SEvan.Yan@Sun.COM 	/* For now: Lets only support one layer of child */
94710923SEvan.Yan@Sun.COM 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
94810923SEvan.Yan@Sun.COM 	req.ra_len = 1;
94910923SEvan.Yan@Sun.COM 	if (ndi_ra_alloc(ddi_get_parent(new_device), &req,
95010923SEvan.Yan@Sun.COM 	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
95110923SEvan.Yan@Sun.COM 	    NDI_RA_PASS) != NDI_SUCCESS) {
95210923SEvan.Yan@Sun.COM 		DEBUG0("ntbridge: Failed to get a bus number\n");
95310923SEvan.Yan@Sun.COM 		return (rc);
95410923SEvan.Yan@Sun.COM 	}
95510923SEvan.Yan@Sun.COM 
95610923SEvan.Yan@Sun.COM 	DEBUG1("ntbridge bus range start  ->[%d]\n", next_bus);
95710923SEvan.Yan@Sun.COM 
95810923SEvan.Yan@Sun.COM 	/*
95910923SEvan.Yan@Sun.COM 	 * Following will change, as we detect more bridges
96010923SEvan.Yan@Sun.COM 	 * on the way.
96110923SEvan.Yan@Sun.COM 	 */
96210923SEvan.Yan@Sun.COM 	bus_range[0] = (int)next_bus;
96310923SEvan.Yan@Sun.COM 	bus_range[1] = (int)next_bus;
96410923SEvan.Yan@Sun.COM 
96510923SEvan.Yan@Sun.COM 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device,
96610923SEvan.Yan@Sun.COM 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
96710923SEvan.Yan@Sun.COM 		DEBUG0("Cannot set ntbridge bus-range property");
96810923SEvan.Yan@Sun.COM 		return (rc);
96910923SEvan.Yan@Sun.COM 	}
97010923SEvan.Yan@Sun.COM 
97110923SEvan.Yan@Sun.COM 	/*
97210923SEvan.Yan@Sun.COM 	 * The other interface (away from the host) will be
97310923SEvan.Yan@Sun.COM 	 * initialized by the nexus driver when it loads.
97410923SEvan.Yan@Sun.COM 	 * We just have to set the registers and the nexus driver
97510923SEvan.Yan@Sun.COM 	 * figures out the rest.
97610923SEvan.Yan@Sun.COM 	 */
97710923SEvan.Yan@Sun.COM 
97810923SEvan.Yan@Sun.COM 	/*
97910923SEvan.Yan@Sun.COM 	 * finally, lets load and attach the driver
98010923SEvan.Yan@Sun.COM 	 * before configuring children of ntbridge.
98110923SEvan.Yan@Sun.COM 	 */
98210923SEvan.Yan@Sun.COM 	rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG);
98310923SEvan.Yan@Sun.COM 	if (rc != NDI_SUCCESS) {
98410923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN,
98510923SEvan.Yan@Sun.COM 		    "pcicfg: Fail: can\'t load non-transparent bridge \
98610923SEvan.Yan@Sun.COM 		    driver.\n");
98710923SEvan.Yan@Sun.COM 		rc = PCICFG_FAILURE;
98810923SEvan.Yan@Sun.COM 		return (rc);
98910923SEvan.Yan@Sun.COM 	}
99010923SEvan.Yan@Sun.COM 	DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
99110923SEvan.Yan@Sun.COM 
99210923SEvan.Yan@Sun.COM 	/* Now set aside pci resources for our children. */
99310923SEvan.Yan@Sun.COM 	if (pcicfg_ntbridge_allocate_resources(new_device) !=
99410923SEvan.Yan@Sun.COM 	    PCICFG_SUCCESS) {
99510923SEvan.Yan@Sun.COM 		max_devs = 0;
99610923SEvan.Yan@Sun.COM 		rc = PCICFG_FAILURE;
99710923SEvan.Yan@Sun.COM 	} else
99810923SEvan.Yan@Sun.COM 		max_devs = PCICFG_MAX_DEVICE;
99910923SEvan.Yan@Sun.COM 
100010923SEvan.Yan@Sun.COM 	/* Probe devices on 2nd bus */
100110923SEvan.Yan@Sun.COM 	for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
100210923SEvan.Yan@Sun.COM 
100310923SEvan.Yan@Sun.COM 		if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
100410923SEvan.Yan@Sun.COM 		    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild)
100510923SEvan.Yan@Sun.COM 		    != NDI_SUCCESS) {
100610923SEvan.Yan@Sun.COM 
100710923SEvan.Yan@Sun.COM 			DEBUG0("pcicfg: Failed to alloc test node\n");
100810923SEvan.Yan@Sun.COM 			rc = PCICFG_FAILURE;
100910923SEvan.Yan@Sun.COM 			break;
101010923SEvan.Yan@Sun.COM 		}
101110923SEvan.Yan@Sun.COM 
101210923SEvan.Yan@Sun.COM 		if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
101310923SEvan.Yan@Sun.COM 		    != DDI_PROP_SUCCESS) {
101410923SEvan.Yan@Sun.COM 			cmn_err(CE_WARN,
101510923SEvan.Yan@Sun.COM 			    "Failed to add conf reg for ntbridge child.\n");
101610923SEvan.Yan@Sun.COM 			(void) ndi_devi_free(new_ntbridgechild);
101710923SEvan.Yan@Sun.COM 			rc = PCICFG_FAILURE;
101810923SEvan.Yan@Sun.COM 			break;
101910923SEvan.Yan@Sun.COM 		}
102010923SEvan.Yan@Sun.COM 
102110923SEvan.Yan@Sun.COM 		if ((rc = pci_config_setup(new_ntbridgechild,
102210923SEvan.Yan@Sun.COM 		    &config_handle)) != PCICFG_SUCCESS) {
102310923SEvan.Yan@Sun.COM 			cmn_err(CE_WARN,
102410923SEvan.Yan@Sun.COM 			    "Cannot map ntbridge child %x\n", devno);
102510923SEvan.Yan@Sun.COM 			(void) ndi_devi_free(new_ntbridgechild);
102610923SEvan.Yan@Sun.COM 			rc = PCICFG_FAILURE;
102710923SEvan.Yan@Sun.COM 			break;
102810923SEvan.Yan@Sun.COM 		}
102910923SEvan.Yan@Sun.COM 
103010923SEvan.Yan@Sun.COM 		/*
103110923SEvan.Yan@Sun.COM 		 * See if there is any PCI HW at this location
103210923SEvan.Yan@Sun.COM 		 * by reading the Vendor ID.  If it returns with 0xffff
103310923SEvan.Yan@Sun.COM 		 * then there is no hardware at this location.
103410923SEvan.Yan@Sun.COM 		 */
103510923SEvan.Yan@Sun.COM 		vid = pci_config_get16(config_handle, PCI_CONF_VENID);
103610923SEvan.Yan@Sun.COM 
103710923SEvan.Yan@Sun.COM 		pci_config_teardown(&config_handle);
103810923SEvan.Yan@Sun.COM 		(void) ndi_devi_free(new_ntbridgechild);
103910923SEvan.Yan@Sun.COM 		if (vid	== 0xffff)
104010923SEvan.Yan@Sun.COM 			continue;
104110923SEvan.Yan@Sun.COM 
104210923SEvan.Yan@Sun.COM 		/* Lets fake attachments points for each child, */
104310923SEvan.Yan@Sun.COM 		if (pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0)
104410923SEvan.Yan@Sun.COM 		    != PCICFG_SUCCESS) {
104510923SEvan.Yan@Sun.COM 			int old_dev = pcicfg_start_devno;
104610923SEvan.Yan@Sun.COM 
104710923SEvan.Yan@Sun.COM 			cmn_err(CE_WARN,
104810923SEvan.Yan@Sun.COM 			"Error configuring ntbridge child dev=%d\n", devno);
104910923SEvan.Yan@Sun.COM 
105010923SEvan.Yan@Sun.COM 			rc = PCICFG_FAILURE;
105110923SEvan.Yan@Sun.COM 			while (old_dev != devno) {
105210923SEvan.Yan@Sun.COM 				if (pcicfg_ntbridge_unconfigure_child(
105310923SEvan.Yan@Sun.COM 				    new_device, old_dev) == PCICFG_FAILURE)
105410923SEvan.Yan@Sun.COM 
105510923SEvan.Yan@Sun.COM 					cmn_err(CE_WARN,
105610923SEvan.Yan@Sun.COM 					    "Unconfig Error ntbridge child "
105710923SEvan.Yan@Sun.COM 					    "dev=%d\n", old_dev);
105810923SEvan.Yan@Sun.COM 				old_dev++;
105910923SEvan.Yan@Sun.COM 			}
106010923SEvan.Yan@Sun.COM 			break;
106110923SEvan.Yan@Sun.COM 		}
106210923SEvan.Yan@Sun.COM 	} /* devno loop */
106310923SEvan.Yan@Sun.COM 	DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
106410923SEvan.Yan@Sun.COM 
106510923SEvan.Yan@Sun.COM 	if (rc != PCICFG_FAILURE)
106610923SEvan.Yan@Sun.COM 		rc = pcicfg_ntbridge_configure_done(new_device);
106710923SEvan.Yan@Sun.COM 	else {
106810923SEvan.Yan@Sun.COM 		pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
106910923SEvan.Yan@Sun.COM 		uint_t			*bus;
107010923SEvan.Yan@Sun.COM 		int			k;
107110923SEvan.Yan@Sun.COM 
107210923SEvan.Yan@Sun.COM 		if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
107310923SEvan.Yan@Sun.COM 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
107410923SEvan.Yan@Sun.COM 		    &k) != DDI_PROP_SUCCESS) {
107510923SEvan.Yan@Sun.COM 			DEBUG0("Failed to read bus-range property\n");
107610923SEvan.Yan@Sun.COM 			rc = PCICFG_FAILURE;
107710923SEvan.Yan@Sun.COM 			return (rc);
107810923SEvan.Yan@Sun.COM 		}
107910923SEvan.Yan@Sun.COM 
108010923SEvan.Yan@Sun.COM 		DEBUG2("Need to free bus [%d] range [%d]\n",
108110923SEvan.Yan@Sun.COM 		    bus[0], bus[1] - bus[0] + 1);
108210923SEvan.Yan@Sun.COM 
108310923SEvan.Yan@Sun.COM 		if (ndi_ra_free(ddi_get_parent(new_device),
108410923SEvan.Yan@Sun.COM 		    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
108510923SEvan.Yan@Sun.COM 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
108610923SEvan.Yan@Sun.COM 			DEBUG0("Failed to free a bus number\n");
108710923SEvan.Yan@Sun.COM 			rc = PCICFG_FAILURE;
108810923SEvan.Yan@Sun.COM 			/*
108910923SEvan.Yan@Sun.COM 			 * Don't forget to free up memory from ddi_getlongprop
109010923SEvan.Yan@Sun.COM 			 */
109110923SEvan.Yan@Sun.COM 			kmem_free((caddr_t)bus, k);
109210923SEvan.Yan@Sun.COM 
109310923SEvan.Yan@Sun.COM 			return (rc);
109410923SEvan.Yan@Sun.COM 		}
109510923SEvan.Yan@Sun.COM 
109610923SEvan.Yan@Sun.COM 		/*
109710923SEvan.Yan@Sun.COM 		 * Since no memory allocations are done for non transparent
109810923SEvan.Yan@Sun.COM 		 * bridges (but instead we just set the handle with the
109910923SEvan.Yan@Sun.COM 		 * already allocated memory, we just need to reset the
110010923SEvan.Yan@Sun.COM 		 * following values before calling the destroy_phdl()
110110923SEvan.Yan@Sun.COM 		 * function next, otherwise the it will try to free
110210923SEvan.Yan@Sun.COM 		 * memory allocated as in case of a transparent bridge.
110310923SEvan.Yan@Sun.COM 		 */
110410923SEvan.Yan@Sun.COM 		entry->memory_len = 0;
110510923SEvan.Yan@Sun.COM 		entry->io_len = 0;
110610923SEvan.Yan@Sun.COM 		/* the following will free hole data. */
110710923SEvan.Yan@Sun.COM 		(void) pcicfg_destroy_phdl(new_device);
110810923SEvan.Yan@Sun.COM 		/*
110910923SEvan.Yan@Sun.COM 		 * Don't forget to free up memory from ddi_getlongprop
111010923SEvan.Yan@Sun.COM 		 */
111110923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)bus, k);
111210923SEvan.Yan@Sun.COM 	}
111310923SEvan.Yan@Sun.COM 
111410923SEvan.Yan@Sun.COM 	/*
111510923SEvan.Yan@Sun.COM 	 * Unload driver just in case child configure failed!
111610923SEvan.Yan@Sun.COM 	 */
111710923SEvan.Yan@Sun.COM 	rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT);
111810923SEvan.Yan@Sun.COM 	DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
111910923SEvan.Yan@Sun.COM 	if (rc1 != NDI_SUCCESS) {
112010923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN,
112110923SEvan.Yan@Sun.COM 		    "pcicfg: can\'t unload ntbridge driver children.\n");
112210923SEvan.Yan@Sun.COM 		rc = PCICFG_FAILURE;
112310923SEvan.Yan@Sun.COM 	}
112410923SEvan.Yan@Sun.COM 
112510923SEvan.Yan@Sun.COM 	return (rc);
112610923SEvan.Yan@Sun.COM }
112710923SEvan.Yan@Sun.COM 
112810923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)112910923SEvan.Yan@Sun.COM pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
113010923SEvan.Yan@Sun.COM {
113110923SEvan.Yan@Sun.COM 	pcicfg_phdl_t		*phdl;
113210923SEvan.Yan@Sun.COM 	ndi_ra_request_t	*mem_request;
113310923SEvan.Yan@Sun.COM 	ndi_ra_request_t	*io_request;
113410923SEvan.Yan@Sun.COM 	uint64_t		boundbase, boundlen;
113510923SEvan.Yan@Sun.COM 
113610923SEvan.Yan@Sun.COM 	phdl = pcicfg_find_phdl(dip);
113710923SEvan.Yan@Sun.COM 	ASSERT(phdl);
113810923SEvan.Yan@Sun.COM 
113910923SEvan.Yan@Sun.COM 	mem_request = &phdl->mem_req;
114010923SEvan.Yan@Sun.COM 	io_request  = &phdl->io_req;
114110923SEvan.Yan@Sun.COM 
114210923SEvan.Yan@Sun.COM 	phdl->error = PCICFG_SUCCESS;
114310923SEvan.Yan@Sun.COM 
114410923SEvan.Yan@Sun.COM 	/* Set Memory space handle for ntbridge */
114510923SEvan.Yan@Sun.COM 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
114610923SEvan.Yan@Sun.COM 	    PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
114710923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN,
114810923SEvan.Yan@Sun.COM 		    "ntbridge: Mem resource information failure\n");
114910923SEvan.Yan@Sun.COM 		phdl->memory_len  = 0;
115010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
115110923SEvan.Yan@Sun.COM 	}
115210923SEvan.Yan@Sun.COM 	mem_request->ra_boundbase = boundbase;
115310923SEvan.Yan@Sun.COM 	mem_request->ra_boundlen = boundbase + boundlen;
115410923SEvan.Yan@Sun.COM 	mem_request->ra_len = boundlen;
115510923SEvan.Yan@Sun.COM 	mem_request->ra_align_mask =
115610923SEvan.Yan@Sun.COM 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
115710923SEvan.Yan@Sun.COM 	mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
115810923SEvan.Yan@Sun.COM 
115910923SEvan.Yan@Sun.COM 	/*
116010923SEvan.Yan@Sun.COM 	 * mem_request->ra_len =
116110923SEvan.Yan@Sun.COM 	 * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
116210923SEvan.Yan@Sun.COM 	 */
116310923SEvan.Yan@Sun.COM 
116410923SEvan.Yan@Sun.COM 	phdl->memory_base = phdl->memory_last = boundbase;
116510923SEvan.Yan@Sun.COM 	phdl->memory_len  = boundlen;
116610923SEvan.Yan@Sun.COM 	phdl->mem_hole.start = phdl->memory_base;
116710923SEvan.Yan@Sun.COM 	phdl->mem_hole.len = mem_request->ra_len;
116810923SEvan.Yan@Sun.COM 	phdl->mem_hole.next = (hole_t *)NULL;
116910923SEvan.Yan@Sun.COM 
117010923SEvan.Yan@Sun.COM 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
117110923SEvan.Yan@Sun.COM 	    boundlen, mem_request->ra_len);
117210923SEvan.Yan@Sun.COM 
117310923SEvan.Yan@Sun.COM 	/* set up a memory resource map for NT bridge */
117410923SEvan.Yan@Sun.COM 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
117510923SEvan.Yan@Sun.COM 		DEBUG0("Can not setup ntbridge memory resource map\n");
117610923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
117710923SEvan.Yan@Sun.COM 	}
117810923SEvan.Yan@Sun.COM 	/* initialize the memory map */
117910923SEvan.Yan@Sun.COM 	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM,
118010923SEvan.Yan@Sun.COM 	    NDI_RA_PASS) != NDI_SUCCESS) {
118110923SEvan.Yan@Sun.COM 		DEBUG0("Can not initalize ntbridge memory resource map\n");
118210923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
118310923SEvan.Yan@Sun.COM 	}
118410923SEvan.Yan@Sun.COM 	/* Set IO space handle for ntbridge */
118510923SEvan.Yan@Sun.COM 	if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
118610923SEvan.Yan@Sun.COM 	    PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
118710923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
118810923SEvan.Yan@Sun.COM 		phdl->io_len  = 0;
118910923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
119010923SEvan.Yan@Sun.COM 	}
119110923SEvan.Yan@Sun.COM 	io_request->ra_len = boundlen;
119210923SEvan.Yan@Sun.COM 	io_request->ra_align_mask =
119310923SEvan.Yan@Sun.COM 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
119410923SEvan.Yan@Sun.COM 	io_request->ra_boundbase = boundbase;
119510923SEvan.Yan@Sun.COM 	io_request->ra_boundlen = boundbase + boundlen;
119610923SEvan.Yan@Sun.COM 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
119710923SEvan.Yan@Sun.COM 
119810923SEvan.Yan@Sun.COM 	/*
119910923SEvan.Yan@Sun.COM 	 * io_request->ra_len =
120010923SEvan.Yan@Sun.COM 	 * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
120110923SEvan.Yan@Sun.COM 	 */
120210923SEvan.Yan@Sun.COM 
120310923SEvan.Yan@Sun.COM 	phdl->io_base = phdl->io_last = (uint32_t)boundbase;
120410923SEvan.Yan@Sun.COM 	phdl->io_len  = (uint32_t)boundlen;
120510923SEvan.Yan@Sun.COM 	phdl->io_hole.start = phdl->io_base;
120610923SEvan.Yan@Sun.COM 	phdl->io_hole.len = io_request->ra_len;
120710923SEvan.Yan@Sun.COM 	phdl->io_hole.next = (hole_t *)NULL;
120810923SEvan.Yan@Sun.COM 
120910923SEvan.Yan@Sun.COM 	DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
121010923SEvan.Yan@Sun.COM 	    boundlen, io_request->ra_len);
121110923SEvan.Yan@Sun.COM 
121210923SEvan.Yan@Sun.COM 	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
121310923SEvan.Yan@Sun.COM 	    phdl->memory_base, phdl->memory_len);
121410923SEvan.Yan@Sun.COM 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
121510923SEvan.Yan@Sun.COM 	    phdl->io_base, phdl->io_len);
121610923SEvan.Yan@Sun.COM 
121710923SEvan.Yan@Sun.COM 	/* set up a IO resource map for NT bridge */
121810923SEvan.Yan@Sun.COM 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
121910923SEvan.Yan@Sun.COM 		DEBUG0("Can not setup ntbridge memory resource map\n");
122010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
122110923SEvan.Yan@Sun.COM 	}
122210923SEvan.Yan@Sun.COM 	/* initialize the IO map */
122310923SEvan.Yan@Sun.COM 	if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO,
122410923SEvan.Yan@Sun.COM 	    NDI_RA_PASS) != NDI_SUCCESS) {
122510923SEvan.Yan@Sun.COM 		DEBUG0("Can not initalize ntbridge memory resource map\n");
122610923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
122710923SEvan.Yan@Sun.COM 	}
122810923SEvan.Yan@Sun.COM 
122910923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
123010923SEvan.Yan@Sun.COM }
123110923SEvan.Yan@Sun.COM 
123210923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)123310923SEvan.Yan@Sun.COM pcicfg_ntbridge_configure_done(dev_info_t *dip)
123410923SEvan.Yan@Sun.COM {
123510923SEvan.Yan@Sun.COM 	pcicfg_range_t range[PCICFG_RANGE_LEN];
123610923SEvan.Yan@Sun.COM 	pcicfg_phdl_t		*entry;
123710923SEvan.Yan@Sun.COM 	uint_t			len;
123810923SEvan.Yan@Sun.COM 	pcicfg_bus_range_t	bus_range;
123910923SEvan.Yan@Sun.COM 	int			new_bus_range[2];
124010923SEvan.Yan@Sun.COM 
124110923SEvan.Yan@Sun.COM 	DEBUG1("Configuring children for %llx\n", dip);
124210923SEvan.Yan@Sun.COM 
124310923SEvan.Yan@Sun.COM 	entry = pcicfg_find_phdl(dip);
124410923SEvan.Yan@Sun.COM 	ASSERT(entry);
124510923SEvan.Yan@Sun.COM 
124610923SEvan.Yan@Sun.COM 	bzero((caddr_t)range,
124710923SEvan.Yan@Sun.COM 	    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
124810923SEvan.Yan@Sun.COM 	range[1].child_hi = range[1].parent_hi |=
124910923SEvan.Yan@Sun.COM 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
125010923SEvan.Yan@Sun.COM 	range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base;
125110923SEvan.Yan@Sun.COM 
125210923SEvan.Yan@Sun.COM 	range[0].child_hi = range[0].parent_hi |=
125310923SEvan.Yan@Sun.COM 	    (PCI_REG_REL_M | PCI_ADDR_IO);
125410923SEvan.Yan@Sun.COM 	range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base;
125510923SEvan.Yan@Sun.COM 
125610923SEvan.Yan@Sun.COM 	len = sizeof (pcicfg_bus_range_t);
125710923SEvan.Yan@Sun.COM 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
125810923SEvan.Yan@Sun.COM 	    "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
125910923SEvan.Yan@Sun.COM 		DEBUG0("no bus-range property\n");
126010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
126110923SEvan.Yan@Sun.COM 	}
126210923SEvan.Yan@Sun.COM 
126310923SEvan.Yan@Sun.COM 	new_bus_range[0] = bus_range.lo;	/* primary bus number */
126410923SEvan.Yan@Sun.COM 	if (entry->highest_bus) {	/* secondary bus number */
126510923SEvan.Yan@Sun.COM 		if (entry->highest_bus < bus_range.lo) {
126610923SEvan.Yan@Sun.COM 			cmn_err(CE_WARN,
126710923SEvan.Yan@Sun.COM 			    "ntbridge bus range invalid !(%d,%d)\n",
126810923SEvan.Yan@Sun.COM 			    bus_range.lo, entry->highest_bus);
126910923SEvan.Yan@Sun.COM 			new_bus_range[1] = bus_range.lo + entry->highest_bus;
127010923SEvan.Yan@Sun.COM 		}
127110923SEvan.Yan@Sun.COM 		else
127210923SEvan.Yan@Sun.COM 			new_bus_range[1] = entry->highest_bus;
127310923SEvan.Yan@Sun.COM 	}
127410923SEvan.Yan@Sun.COM 	else
127510923SEvan.Yan@Sun.COM 		new_bus_range[1] = bus_range.hi;
127610923SEvan.Yan@Sun.COM 
127710923SEvan.Yan@Sun.COM 	DEBUG2("ntbridge: bus range lo=%x, hi=%x\n",
127810923SEvan.Yan@Sun.COM 	    new_bus_range[0], new_bus_range[1]);
127910923SEvan.Yan@Sun.COM 
128010923SEvan.Yan@Sun.COM 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
128110923SEvan.Yan@Sun.COM 	    "bus-range", new_bus_range, 2) != DDI_SUCCESS) {
128210923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set bus-range property");
128310923SEvan.Yan@Sun.COM 		entry->error = PCICFG_FAILURE;
128410923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
128510923SEvan.Yan@Sun.COM 	}
128610923SEvan.Yan@Sun.COM 
128710923SEvan.Yan@Sun.COM #ifdef DEBUG
128810923SEvan.Yan@Sun.COM 	{
128910923SEvan.Yan@Sun.COM 		uint64_t	unused;
129010923SEvan.Yan@Sun.COM 		unused = pcicfg_unused_space(&entry->io_hole, &len);
129110923SEvan.Yan@Sun.COM 		DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
129210923SEvan.Yan@Sun.COM 		    unused, len);
129310923SEvan.Yan@Sun.COM 	}
129410923SEvan.Yan@Sun.COM #endif
129510923SEvan.Yan@Sun.COM 
129610923SEvan.Yan@Sun.COM 	range[0].size_lo = entry->io_len;
129710923SEvan.Yan@Sun.COM 	if (pcicfg_update_ranges_prop(dip, &range[0])) {
129810923SEvan.Yan@Sun.COM 		DEBUG0("Failed to update ranges (i/o)\n");
129910923SEvan.Yan@Sun.COM 		entry->error = PCICFG_FAILURE;
130010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
130110923SEvan.Yan@Sun.COM 	}
130210923SEvan.Yan@Sun.COM 
130310923SEvan.Yan@Sun.COM #ifdef DEBUG
130410923SEvan.Yan@Sun.COM 	{
130510923SEvan.Yan@Sun.COM 		uint64_t	unused;
130610923SEvan.Yan@Sun.COM 		unused = pcicfg_unused_space(&entry->mem_hole, &len);
130710923SEvan.Yan@Sun.COM 		DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
130810923SEvan.Yan@Sun.COM 		    unused, len);
130910923SEvan.Yan@Sun.COM 	}
131010923SEvan.Yan@Sun.COM #endif
131110923SEvan.Yan@Sun.COM 
131210923SEvan.Yan@Sun.COM 	range[1].size_lo = entry->memory_len;
131310923SEvan.Yan@Sun.COM 	if (pcicfg_update_ranges_prop(dip, &range[1])) {
131410923SEvan.Yan@Sun.COM 		DEBUG0("Failed to update ranges (memory)\n");
131510923SEvan.Yan@Sun.COM 		entry->error = PCICFG_FAILURE;
131610923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
131710923SEvan.Yan@Sun.COM 	}
131810923SEvan.Yan@Sun.COM 
131910923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
132010923SEvan.Yan@Sun.COM }
132110923SEvan.Yan@Sun.COM 
132210923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)132310923SEvan.Yan@Sun.COM pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
132410923SEvan.Yan@Sun.COM {
132510923SEvan.Yan@Sun.COM 
132610923SEvan.Yan@Sun.COM 	dev_info_t	*new_ntbridgechild;
132710923SEvan.Yan@Sun.COM 	int 		len, bus;
132810923SEvan.Yan@Sun.COM 	uint16_t	vid;
132910923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	config_handle;
133010923SEvan.Yan@Sun.COM 	pcicfg_bus_range_t pci_bus_range;
133110923SEvan.Yan@Sun.COM 
133210923SEvan.Yan@Sun.COM 	len = sizeof (pcicfg_bus_range_t);
133310923SEvan.Yan@Sun.COM 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
133410923SEvan.Yan@Sun.COM 	    "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
133510923SEvan.Yan@Sun.COM 		DEBUG0("no bus-range property\n");
133610923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
133710923SEvan.Yan@Sun.COM 	}
133810923SEvan.Yan@Sun.COM 
133910923SEvan.Yan@Sun.COM 	bus = pci_bus_range.lo; /* primary bus number of this bus node */
134010923SEvan.Yan@Sun.COM 
134110923SEvan.Yan@Sun.COM 	if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
134210923SEvan.Yan@Sun.COM 	    (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) {
134310923SEvan.Yan@Sun.COM 
134410923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg: Failed to alloc test node\n");
134510923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
134610923SEvan.Yan@Sun.COM 	}
134710923SEvan.Yan@Sun.COM 
134810923SEvan.Yan@Sun.COM 	if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
134910923SEvan.Yan@Sun.COM 	    != DDI_PROP_SUCCESS) {
135010923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN,
135110923SEvan.Yan@Sun.COM 		"Unconfigure: Failed to add conf reg prop for ntbridge "
135210923SEvan.Yan@Sun.COM 		    "child.\n");
135310923SEvan.Yan@Sun.COM 		(void) ndi_devi_free(new_ntbridgechild);
135410923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
135510923SEvan.Yan@Sun.COM 	}
135610923SEvan.Yan@Sun.COM 
135710923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(new_ntbridgechild, &config_handle)
135810923SEvan.Yan@Sun.COM 	    != DDI_SUCCESS) {
135910923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN,
136010923SEvan.Yan@Sun.COM 		    "pcicfg: Cannot map ntbridge child %x\n", devno);
136110923SEvan.Yan@Sun.COM 		(void) ndi_devi_free(new_ntbridgechild);
136210923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
136310923SEvan.Yan@Sun.COM 	}
136410923SEvan.Yan@Sun.COM 
136510923SEvan.Yan@Sun.COM 	/*
136610923SEvan.Yan@Sun.COM 	 * See if there is any PCI HW at this location
136710923SEvan.Yan@Sun.COM 	 * by reading the Vendor ID.  If it returns with 0xffff
136810923SEvan.Yan@Sun.COM 	 * then there is no hardware at this location.
136910923SEvan.Yan@Sun.COM 	 */
137010923SEvan.Yan@Sun.COM 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
137110923SEvan.Yan@Sun.COM 
137210923SEvan.Yan@Sun.COM 	pci_config_teardown(&config_handle);
137310923SEvan.Yan@Sun.COM 	(void) ndi_devi_free(new_ntbridgechild);
137410923SEvan.Yan@Sun.COM 	if (vid	== 0xffff)
137510923SEvan.Yan@Sun.COM 		return (PCICFG_NODEVICE);
137610923SEvan.Yan@Sun.COM 
137710923SEvan.Yan@Sun.COM 	return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
137810923SEvan.Yan@Sun.COM }
137910923SEvan.Yan@Sun.COM 
138010923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_unconfigure(dev_info_t * dip)138110923SEvan.Yan@Sun.COM pcicfg_ntbridge_unconfigure(dev_info_t *dip)
138210923SEvan.Yan@Sun.COM {
138310923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
138410923SEvan.Yan@Sun.COM 	uint_t			*bus;
138510923SEvan.Yan@Sun.COM 	int			k, rc = PCICFG_FAILURE;
138610923SEvan.Yan@Sun.COM 
138710923SEvan.Yan@Sun.COM 	if (entry->memory_len)
138810923SEvan.Yan@Sun.COM 		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
138910923SEvan.Yan@Sun.COM 			DEBUG1("cannot destroy ntbridge memory map size=%x\n",
139010923SEvan.Yan@Sun.COM 			    entry->memory_len);
139110923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
139210923SEvan.Yan@Sun.COM 		}
139310923SEvan.Yan@Sun.COM 	if (entry->io_len)
139410923SEvan.Yan@Sun.COM 		if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
139510923SEvan.Yan@Sun.COM 			DEBUG1("cannot destroy ntbridge io map size=%x\n",
139610923SEvan.Yan@Sun.COM 			    entry->io_len);
139710923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
139810923SEvan.Yan@Sun.COM 		}
139910923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
140010923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
140110923SEvan.Yan@Sun.COM 	    &k) != DDI_PROP_SUCCESS) {
140210923SEvan.Yan@Sun.COM 		DEBUG0("ntbridge: Failed to read bus-range property\n");
140310923SEvan.Yan@Sun.COM 		return (rc);
140410923SEvan.Yan@Sun.COM 	}
140510923SEvan.Yan@Sun.COM 
140610923SEvan.Yan@Sun.COM 	DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
140710923SEvan.Yan@Sun.COM 	    bus[0], bus[1] - bus[0] + 1);
140810923SEvan.Yan@Sun.COM 
140910923SEvan.Yan@Sun.COM 	if (ndi_ra_free(ddi_get_parent(dip),
141010923SEvan.Yan@Sun.COM 	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
141110923SEvan.Yan@Sun.COM 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
141210923SEvan.Yan@Sun.COM 		DEBUG0("ntbridge: Failed to free a bus number\n");
141310923SEvan.Yan@Sun.COM 		/*
141410923SEvan.Yan@Sun.COM 		 * Don't forget to free up memory from ddi_getlongprop
141510923SEvan.Yan@Sun.COM 		 */
141610923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)bus, k);
141710923SEvan.Yan@Sun.COM 
141810923SEvan.Yan@Sun.COM 		return (rc);
141910923SEvan.Yan@Sun.COM 	}
142010923SEvan.Yan@Sun.COM 
142110923SEvan.Yan@Sun.COM 	/*
142210923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
142310923SEvan.Yan@Sun.COM 	 */
142410923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)bus, k);
142510923SEvan.Yan@Sun.COM 
142610923SEvan.Yan@Sun.COM 	/*
142710923SEvan.Yan@Sun.COM 	 * Since our resources will be freed at the parent level,
142810923SEvan.Yan@Sun.COM 	 * just reset these values.
142910923SEvan.Yan@Sun.COM 	 */
143010923SEvan.Yan@Sun.COM 	entry->memory_len = 0;
143110923SEvan.Yan@Sun.COM 	entry->io_len = 0;
143210923SEvan.Yan@Sun.COM 	/* the following will also free hole data. */
143310923SEvan.Yan@Sun.COM 	return (pcicfg_destroy_phdl(dip));
143410923SEvan.Yan@Sun.COM 
143510923SEvan.Yan@Sun.COM }
143610923SEvan.Yan@Sun.COM 
143710923SEvan.Yan@Sun.COM static int
pcicfg_is_ntbridge(dev_info_t * dip)143810923SEvan.Yan@Sun.COM pcicfg_is_ntbridge(dev_info_t *dip)
143910923SEvan.Yan@Sun.COM {
144010923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	config_handle;
144110923SEvan.Yan@Sun.COM 	uint8_t		class, subclass;
144210923SEvan.Yan@Sun.COM 	int		rc = DDI_SUCCESS;
144310923SEvan.Yan@Sun.COM 
144410923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) {
144510923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN,
144610923SEvan.Yan@Sun.COM 		    "pcicfg: cannot map config space, to get map type\n");
144710923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
144810923SEvan.Yan@Sun.COM 	}
144910923SEvan.Yan@Sun.COM 	class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
145010923SEvan.Yan@Sun.COM 	subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
145110923SEvan.Yan@Sun.COM 
145210923SEvan.Yan@Sun.COM 	/* check for class=6, subclass=9, for non transparent bridges.  */
145310923SEvan.Yan@Sun.COM 	if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
145410923SEvan.Yan@Sun.COM 		rc = DDI_FAILURE;
145510923SEvan.Yan@Sun.COM 
145610923SEvan.Yan@Sun.COM 	DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
145710923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_VENID),
145810923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_DEVID),
145910923SEvan.Yan@Sun.COM 	    rc);
146010923SEvan.Yan@Sun.COM 	pci_config_teardown(&config_handle);
146110923SEvan.Yan@Sun.COM 	return (rc);
146210923SEvan.Yan@Sun.COM }
146310923SEvan.Yan@Sun.COM 
146410923SEvan.Yan@Sun.COM /*
146510923SEvan.Yan@Sun.COM  * this function is called only for SPARC platforms, where we may have
146610923SEvan.Yan@Sun.COM  * a mix n' match of direct vs indirectly mapped configuration space.
146710923SEvan.Yan@Sun.COM  * On x86, this function does not get called. We always return TRUE
146810923SEvan.Yan@Sun.COM  * via a macro for x86.
146910923SEvan.Yan@Sun.COM  */
147010923SEvan.Yan@Sun.COM /*ARGSUSED*/
147110923SEvan.Yan@Sun.COM static int
pcicfg_indirect_map(dev_info_t * dip)147210923SEvan.Yan@Sun.COM pcicfg_indirect_map(dev_info_t *dip)
147310923SEvan.Yan@Sun.COM {
147410923SEvan.Yan@Sun.COM #if defined(__sparc)
147510923SEvan.Yan@Sun.COM 	int rc = DDI_FAILURE;
147610923SEvan.Yan@Sun.COM 
147710923SEvan.Yan@Sun.COM 	if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
147810923SEvan.Yan@Sun.COM 	    PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
147910923SEvan.Yan@Sun.COM 		rc = DDI_SUCCESS;
148010923SEvan.Yan@Sun.COM 	else
148110923SEvan.Yan@Sun.COM 		if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
148210923SEvan.Yan@Sun.COM 		    0, PCI_BUS_CONF_MAP_PROP,
148310923SEvan.Yan@Sun.COM 		    DDI_FAILURE) != DDI_FAILURE)
148410923SEvan.Yan@Sun.COM 			rc = DDI_SUCCESS;
148510923SEvan.Yan@Sun.COM 	DEBUG1("pci conf map = %d", rc);
148610923SEvan.Yan@Sun.COM 	return (rc);
148710923SEvan.Yan@Sun.COM #else
148810923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
148910923SEvan.Yan@Sun.COM #endif
149010923SEvan.Yan@Sun.COM }
149110923SEvan.Yan@Sun.COM 
149210923SEvan.Yan@Sun.COM static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)149310923SEvan.Yan@Sun.COM pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
149410923SEvan.Yan@Sun.COM 				uint64_t *boundlen, uint_t space_type)
149510923SEvan.Yan@Sun.COM {
149610923SEvan.Yan@Sun.COM 	int		length, found = DDI_FAILURE, acount, i, ibridge;
149710923SEvan.Yan@Sun.COM 	pci_regspec_t	*assigned;
149810923SEvan.Yan@Sun.COM 
149910923SEvan.Yan@Sun.COM 	if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
150010923SEvan.Yan@Sun.COM 		return (found);
150110923SEvan.Yan@Sun.COM 
150210923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
150310923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
150410923SEvan.Yan@Sun.COM 	    &length) != DDI_PROP_SUCCESS) {
150510923SEvan.Yan@Sun.COM 		DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
150610923SEvan.Yan@Sun.COM 		return (found);
150710923SEvan.Yan@Sun.COM 	}
150810923SEvan.Yan@Sun.COM 	DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
150910923SEvan.Yan@Sun.COM 	    ddi_driver_name(dip));
151010923SEvan.Yan@Sun.COM 
151110923SEvan.Yan@Sun.COM 	acount = length / sizeof (pci_regspec_t);
151210923SEvan.Yan@Sun.COM 
151310923SEvan.Yan@Sun.COM 	for (i = 0; i < acount; i++) {
151410923SEvan.Yan@Sun.COM 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
151510923SEvan.Yan@Sun.COM 		    pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
151610923SEvan.Yan@Sun.COM 		    (space_type == PCI_BASE_SPACE_MEM)) {
151710923SEvan.Yan@Sun.COM 			found = DDI_SUCCESS;
151810923SEvan.Yan@Sun.COM 			break;
151910923SEvan.Yan@Sun.COM 		} else {
152010923SEvan.Yan@Sun.COM 			if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
152110923SEvan.Yan@Sun.COM 			    pcicfg_indirect_map_devs[ibridge].\
152210923SEvan.Yan@Sun.COM 			    io_range_bar_offset) &&
152310923SEvan.Yan@Sun.COM 			    (space_type == PCI_BASE_SPACE_IO)) {
152410923SEvan.Yan@Sun.COM 				found = DDI_SUCCESS;
152510923SEvan.Yan@Sun.COM 				break;
152610923SEvan.Yan@Sun.COM 			}
152710923SEvan.Yan@Sun.COM 		}
152810923SEvan.Yan@Sun.COM 	}
152910923SEvan.Yan@Sun.COM 	DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
153010923SEvan.Yan@Sun.COM 	    space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
153110923SEvan.Yan@Sun.COM 
153210923SEvan.Yan@Sun.COM 	if (found == DDI_SUCCESS)  {
153310923SEvan.Yan@Sun.COM 		*boundbase = assigned[i].pci_phys_low;
153410923SEvan.Yan@Sun.COM 		*boundlen = assigned[i].pci_size_low;
153510923SEvan.Yan@Sun.COM 	}
153610923SEvan.Yan@Sun.COM 
153710923SEvan.Yan@Sun.COM 	kmem_free(assigned, length);
153810923SEvan.Yan@Sun.COM 	return (found);
153910923SEvan.Yan@Sun.COM }
154010923SEvan.Yan@Sun.COM 
154110923SEvan.Yan@Sun.COM /*
154210923SEvan.Yan@Sun.COM  * This will turn  resources allocated by pcicfg_configure()
154310923SEvan.Yan@Sun.COM  * and remove the device tree from the Hotplug Connection (CN)
154410923SEvan.Yan@Sun.COM  * and below.  The routine assumes the devices have their
154510923SEvan.Yan@Sun.COM  * drivers detached.
154610923SEvan.Yan@Sun.COM  */
154710923SEvan.Yan@Sun.COM int
pcicfg_unconfigure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)154810923SEvan.Yan@Sun.COM pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
154910923SEvan.Yan@Sun.COM     pcicfg_flags_t flags)
155010923SEvan.Yan@Sun.COM {
155110923SEvan.Yan@Sun.COM 	dev_info_t *child_dip;
155210923SEvan.Yan@Sun.COM 	int func;
155310923SEvan.Yan@Sun.COM 	int i;
155410923SEvan.Yan@Sun.COM 	int max_function;
155510923SEvan.Yan@Sun.COM 	int trans_device;
155611245SZhijun.Fu@Sun.COM 	int circ;
155711245SZhijun.Fu@Sun.COM 	boolean_t is_pcie;
155810923SEvan.Yan@Sun.COM 
155910923SEvan.Yan@Sun.COM 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
156010923SEvan.Yan@Sun.COM 		max_function = PCICFG_MAX_ARI_FUNCTION;
156110923SEvan.Yan@Sun.COM 	else
156210923SEvan.Yan@Sun.COM 		max_function = PCICFG_MAX_FUNCTION;
156310923SEvan.Yan@Sun.COM 
156410923SEvan.Yan@Sun.COM 	/*
156510923SEvan.Yan@Sun.COM 	 * Cycle through devices to make sure none are busy.
156610923SEvan.Yan@Sun.COM 	 * If a single device is busy fail the whole unconfigure.
156710923SEvan.Yan@Sun.COM 	 */
156811245SZhijun.Fu@Sun.COM 	is_pcie = is_pcie_fabric(devi);
156911245SZhijun.Fu@Sun.COM 
157011245SZhijun.Fu@Sun.COM 	ndi_devi_enter(devi, &circ);
157110923SEvan.Yan@Sun.COM 	for (func = 0; func < max_function; func++) {
157210923SEvan.Yan@Sun.COM 
157310923SEvan.Yan@Sun.COM 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
157410923SEvan.Yan@Sun.COM 			trans_device = func >> 3; /* ARI Device */
157510923SEvan.Yan@Sun.COM 		else
157610923SEvan.Yan@Sun.COM 			trans_device = device;
157710923SEvan.Yan@Sun.COM 
157810923SEvan.Yan@Sun.COM 		if ((child_dip = pcicfg_devi_find(devi, trans_device,
157910923SEvan.Yan@Sun.COM 		    (func & 0x7))) == NULL)
158010923SEvan.Yan@Sun.COM 			continue;
158110923SEvan.Yan@Sun.COM 
158210923SEvan.Yan@Sun.COM 		if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
158310923SEvan.Yan@Sun.COM 			continue;
158410923SEvan.Yan@Sun.COM 		/*
158510923SEvan.Yan@Sun.COM 		 * Device function is busy. Before returning we have to
158610923SEvan.Yan@Sun.COM 		 * put all functions back online which were taken
158710923SEvan.Yan@Sun.COM 		 * offline during the process.
158810923SEvan.Yan@Sun.COM 		 */
158910923SEvan.Yan@Sun.COM 		DEBUG2("Device [0x%x] function [%x] is busy\n", device, func);
159010923SEvan.Yan@Sun.COM 		/*
159110923SEvan.Yan@Sun.COM 		 * If we are only asked to offline one specific function,
159210923SEvan.Yan@Sun.COM 		 * and that fails, we just simply return.
159310923SEvan.Yan@Sun.COM 		 */
159410923SEvan.Yan@Sun.COM 		if (function != PCICFG_ALL_FUNC)
159510923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
159610923SEvan.Yan@Sun.COM 
159710923SEvan.Yan@Sun.COM 		for (i = 0; i < func; i++) {
159810923SEvan.Yan@Sun.COM 
159910923SEvan.Yan@Sun.COM 			if (max_function == PCICFG_MAX_ARI_FUNCTION)
160010923SEvan.Yan@Sun.COM 				trans_device = i >> 3;
160110923SEvan.Yan@Sun.COM 
160210923SEvan.Yan@Sun.COM 			if ((child_dip =
160310923SEvan.Yan@Sun.COM 			    pcicfg_devi_find(devi, trans_device, (i & 7)))
160410923SEvan.Yan@Sun.COM 			    == NULL) {
160510923SEvan.Yan@Sun.COM 				DEBUG0(
160610923SEvan.Yan@Sun.COM 				    "No more devices to put back on line!!\n");
160710923SEvan.Yan@Sun.COM 				/*
160810923SEvan.Yan@Sun.COM 				 * Made it through all functions
160910923SEvan.Yan@Sun.COM 				 */
161010923SEvan.Yan@Sun.COM 				continue;
161110923SEvan.Yan@Sun.COM 			}
161210923SEvan.Yan@Sun.COM 			if (ndi_devi_online(child_dip, NDI_CONFIG)
161310923SEvan.Yan@Sun.COM 			    != NDI_SUCCESS) {
161410923SEvan.Yan@Sun.COM 				DEBUG0("Failed to put back devices state\n");
161511245SZhijun.Fu@Sun.COM 				goto fail;
161610923SEvan.Yan@Sun.COM 			}
161710923SEvan.Yan@Sun.COM 		}
161811245SZhijun.Fu@Sun.COM 		goto fail;
161910923SEvan.Yan@Sun.COM 	}
162010923SEvan.Yan@Sun.COM 
162110923SEvan.Yan@Sun.COM 	/*
162210923SEvan.Yan@Sun.COM 	 * Now, tear down all devinfo nodes for this Connector.
162310923SEvan.Yan@Sun.COM 	 */
162410923SEvan.Yan@Sun.COM 	for (func = 0; func < max_function; func++) {
162510923SEvan.Yan@Sun.COM 
162610923SEvan.Yan@Sun.COM 		if (max_function == PCICFG_MAX_ARI_FUNCTION)
162710923SEvan.Yan@Sun.COM 			trans_device = func >> 3; /* ARI Device */
162810923SEvan.Yan@Sun.COM 		else
162910923SEvan.Yan@Sun.COM 			trans_device = device;
163010923SEvan.Yan@Sun.COM 
163110923SEvan.Yan@Sun.COM 		if ((child_dip = pcicfg_devi_find(devi,
163210923SEvan.Yan@Sun.COM 		    trans_device, (func & 7))) == NULL) {
163310923SEvan.Yan@Sun.COM 			DEBUG0("No more devices to tear down!\n");
163410923SEvan.Yan@Sun.COM 			continue;
163510923SEvan.Yan@Sun.COM 		}
163610923SEvan.Yan@Sun.COM 
163710923SEvan.Yan@Sun.COM 		DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
163810923SEvan.Yan@Sun.COM 		    trans_device, (func & 7));
163910923SEvan.Yan@Sun.COM 
164010923SEvan.Yan@Sun.COM 		if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
164110923SEvan.Yan@Sun.COM 			if (pcicfg_ntbridge_unconfigure(child_dip) !=
164210923SEvan.Yan@Sun.COM 			    PCICFG_SUCCESS) {
164310923SEvan.Yan@Sun.COM 				cmn_err(CE_WARN,
164410923SEvan.Yan@Sun.COM 				    "ntbridge: unconfigure failed\n");
164511245SZhijun.Fu@Sun.COM 				goto fail;
164610923SEvan.Yan@Sun.COM 			}
164710923SEvan.Yan@Sun.COM 
164811245SZhijun.Fu@Sun.COM 		if (pcicfg_teardown_device(child_dip, flags, is_pcie)
164910923SEvan.Yan@Sun.COM 		    != PCICFG_SUCCESS) {
165010923SEvan.Yan@Sun.COM 			DEBUG2("Failed to tear down device [0x%x]"
165110923SEvan.Yan@Sun.COM 			    "function [0x%x]\n",
165210923SEvan.Yan@Sun.COM 			    trans_device, func & 7);
165311245SZhijun.Fu@Sun.COM 			goto fail;
165410923SEvan.Yan@Sun.COM 		}
165510923SEvan.Yan@Sun.COM 	}
165610923SEvan.Yan@Sun.COM 
165710923SEvan.Yan@Sun.COM 	if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
165810923SEvan.Yan@Sun.COM 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
165910923SEvan.Yan@Sun.COM 		(void) pcie_ari_disable(devi);
166010923SEvan.Yan@Sun.COM 	}
166110923SEvan.Yan@Sun.COM 
166211245SZhijun.Fu@Sun.COM 	ndi_devi_exit(devi, circ);
166310923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
166411245SZhijun.Fu@Sun.COM 
166511245SZhijun.Fu@Sun.COM fail:
166611245SZhijun.Fu@Sun.COM 	ndi_devi_exit(devi, circ);
166711245SZhijun.Fu@Sun.COM 	return (PCICFG_FAILURE);
166810923SEvan.Yan@Sun.COM }
166910923SEvan.Yan@Sun.COM 
167010923SEvan.Yan@Sun.COM static int
pcicfg_teardown_device(dev_info_t * dip,pcicfg_flags_t flags,boolean_t is_pcie)167111245SZhijun.Fu@Sun.COM pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
167210923SEvan.Yan@Sun.COM {
167310923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	config_handle;
167410923SEvan.Yan@Sun.COM 
167510923SEvan.Yan@Sun.COM 	/*
167610923SEvan.Yan@Sun.COM 	 * Free up resources associated with 'dip'
167710923SEvan.Yan@Sun.COM 	 */
167810923SEvan.Yan@Sun.COM 	if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
167910923SEvan.Yan@Sun.COM 		DEBUG0("Failed to free resources\n");
168010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
168110923SEvan.Yan@Sun.COM 	}
168210923SEvan.Yan@Sun.COM 
168310923SEvan.Yan@Sun.COM 	/*
168410923SEvan.Yan@Sun.COM 	 * This will disable the device
168510923SEvan.Yan@Sun.COM 	 */
168610923SEvan.Yan@Sun.COM 	if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) {
168710923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
168810923SEvan.Yan@Sun.COM 	}
168910923SEvan.Yan@Sun.COM 
169010923SEvan.Yan@Sun.COM 	pcicfg_device_off(config_handle);
169110923SEvan.Yan@Sun.COM 	pci_config_teardown(&config_handle);
169210923SEvan.Yan@Sun.COM 
169310923SEvan.Yan@Sun.COM 	/*
169411245SZhijun.Fu@Sun.COM 	 * free pcie_bus_t for the sub-tree
169511245SZhijun.Fu@Sun.COM 	 */
169611245SZhijun.Fu@Sun.COM 	if (is_pcie) {
169711245SZhijun.Fu@Sun.COM 		if (ddi_get_child(dip) != NULL)
169811245SZhijun.Fu@Sun.COM 			pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
169911245SZhijun.Fu@Sun.COM 
170011245SZhijun.Fu@Sun.COM 		pcie_fini_bus(dip, PCIE_BUS_ALL);
170111245SZhijun.Fu@Sun.COM 	}
170211245SZhijun.Fu@Sun.COM 
170311245SZhijun.Fu@Sun.COM 	/*
170410923SEvan.Yan@Sun.COM 	 * The framework provides this routine which can
170510923SEvan.Yan@Sun.COM 	 * tear down a sub-tree.
170610923SEvan.Yan@Sun.COM 	 */
170710923SEvan.Yan@Sun.COM 	if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
170810923SEvan.Yan@Sun.COM 		DEBUG0("Failed to offline and remove node\n");
170910923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
171010923SEvan.Yan@Sun.COM 	}
171110923SEvan.Yan@Sun.COM 
171210923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
171310923SEvan.Yan@Sun.COM }
171410923SEvan.Yan@Sun.COM 
171510923SEvan.Yan@Sun.COM /*
171610923SEvan.Yan@Sun.COM  * BEGIN GENERIC SUPPORT ROUTINES
171710923SEvan.Yan@Sun.COM  */
171810923SEvan.Yan@Sun.COM static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)171910923SEvan.Yan@Sun.COM pcicfg_find_phdl(dev_info_t *dip)
172010923SEvan.Yan@Sun.COM {
172110923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *entry;
172210923SEvan.Yan@Sun.COM 	mutex_enter(&pcicfg_list_mutex);
172310923SEvan.Yan@Sun.COM 	for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
172410923SEvan.Yan@Sun.COM 		if (entry->dip == dip) {
172510923SEvan.Yan@Sun.COM 			mutex_exit(&pcicfg_list_mutex);
172610923SEvan.Yan@Sun.COM 			return (entry);
172710923SEvan.Yan@Sun.COM 		}
172810923SEvan.Yan@Sun.COM 	}
172910923SEvan.Yan@Sun.COM 	mutex_exit(&pcicfg_list_mutex);
173010923SEvan.Yan@Sun.COM 
173110923SEvan.Yan@Sun.COM 	/*
173210923SEvan.Yan@Sun.COM 	 * Did'nt find entry - create one
173310923SEvan.Yan@Sun.COM 	 */
173410923SEvan.Yan@Sun.COM 	return (pcicfg_create_phdl(dip));
173510923SEvan.Yan@Sun.COM }
173610923SEvan.Yan@Sun.COM 
173710923SEvan.Yan@Sun.COM static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)173810923SEvan.Yan@Sun.COM pcicfg_create_phdl(dev_info_t *dip)
173910923SEvan.Yan@Sun.COM {
174010923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *new;
174110923SEvan.Yan@Sun.COM 
174210923SEvan.Yan@Sun.COM 	new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t),
174310923SEvan.Yan@Sun.COM 	    KM_SLEEP);
174410923SEvan.Yan@Sun.COM 
174510923SEvan.Yan@Sun.COM 	new->dip = dip;
174610923SEvan.Yan@Sun.COM 	mutex_enter(&pcicfg_list_mutex);
174710923SEvan.Yan@Sun.COM 	new->next = pcicfg_phdl_list;
174810923SEvan.Yan@Sun.COM 	pcicfg_phdl_list = new;
174910923SEvan.Yan@Sun.COM 	mutex_exit(&pcicfg_list_mutex);
175010923SEvan.Yan@Sun.COM 
175110923SEvan.Yan@Sun.COM 	return (new);
175210923SEvan.Yan@Sun.COM }
175310923SEvan.Yan@Sun.COM 
175410923SEvan.Yan@Sun.COM static int
pcicfg_destroy_phdl(dev_info_t * dip)175510923SEvan.Yan@Sun.COM pcicfg_destroy_phdl(dev_info_t *dip)
175610923SEvan.Yan@Sun.COM {
175710923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *entry;
175810923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *follow = NULL;
175910923SEvan.Yan@Sun.COM 
176010923SEvan.Yan@Sun.COM 	mutex_enter(&pcicfg_list_mutex);
176110923SEvan.Yan@Sun.COM 	for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
176210923SEvan.Yan@Sun.COM 	    entry = entry->next) {
176310923SEvan.Yan@Sun.COM 		if (entry->dip == dip) {
176410923SEvan.Yan@Sun.COM 			if (entry == pcicfg_phdl_list) {
176510923SEvan.Yan@Sun.COM 				pcicfg_phdl_list = entry->next;
176610923SEvan.Yan@Sun.COM 			} else {
176710923SEvan.Yan@Sun.COM 				follow->next = entry->next;
176810923SEvan.Yan@Sun.COM 			}
176910923SEvan.Yan@Sun.COM 			/*
177010923SEvan.Yan@Sun.COM 			 * If this entry has any allocated memory
177110923SEvan.Yan@Sun.COM 			 * or IO space associated with it, that
177210923SEvan.Yan@Sun.COM 			 * must be freed up.
177310923SEvan.Yan@Sun.COM 			 */
177410923SEvan.Yan@Sun.COM 			if (entry->memory_len > 0) {
177510923SEvan.Yan@Sun.COM 				(void) ndi_ra_free(ddi_get_parent(dip),
177610923SEvan.Yan@Sun.COM 				    entry->memory_base,
177710923SEvan.Yan@Sun.COM 				    entry->memory_len,
177810923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
177910923SEvan.Yan@Sun.COM 			}
178010923SEvan.Yan@Sun.COM 			pcicfg_free_hole(&entry->mem_hole);
178110923SEvan.Yan@Sun.COM 
178210923SEvan.Yan@Sun.COM 			if (entry->io_len > 0) {
178310923SEvan.Yan@Sun.COM 				(void) ndi_ra_free(ddi_get_parent(dip),
178410923SEvan.Yan@Sun.COM 				    entry->io_base,
178510923SEvan.Yan@Sun.COM 				    entry->io_len,
178610923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_IO, NDI_RA_PASS);
178710923SEvan.Yan@Sun.COM 			}
178810923SEvan.Yan@Sun.COM 			pcicfg_free_hole(&entry->io_hole);
178910923SEvan.Yan@Sun.COM 
179010923SEvan.Yan@Sun.COM 			/*
179110923SEvan.Yan@Sun.COM 			 * Destroy this entry
179210923SEvan.Yan@Sun.COM 			 */
179310923SEvan.Yan@Sun.COM 			kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
179410923SEvan.Yan@Sun.COM 			mutex_exit(&pcicfg_list_mutex);
179510923SEvan.Yan@Sun.COM 			return (PCICFG_SUCCESS);
179610923SEvan.Yan@Sun.COM 		}
179710923SEvan.Yan@Sun.COM 	}
179810923SEvan.Yan@Sun.COM 	mutex_exit(&pcicfg_list_mutex);
179910923SEvan.Yan@Sun.COM 	/*
180010923SEvan.Yan@Sun.COM 	 * Did'nt find the entry
180110923SEvan.Yan@Sun.COM 	 */
180210923SEvan.Yan@Sun.COM 	return (PCICFG_FAILURE);
180310923SEvan.Yan@Sun.COM }
180410923SEvan.Yan@Sun.COM 
180510923SEvan.Yan@Sun.COM static int
pcicfg_program_ap(dev_info_t * dip)180610923SEvan.Yan@Sun.COM pcicfg_program_ap(dev_info_t *dip)
180710923SEvan.Yan@Sun.COM {
180810923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *phdl;
180910923SEvan.Yan@Sun.COM 	uint8_t header_type;
181010923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
181110923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *entry;
181210923SEvan.Yan@Sun.COM 
181310923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
181410923SEvan.Yan@Sun.COM 		DEBUG0("Failed to map config space!\n");
181510923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
181610923SEvan.Yan@Sun.COM 
181710923SEvan.Yan@Sun.COM 	}
181810923SEvan.Yan@Sun.COM 
181910923SEvan.Yan@Sun.COM 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
182010923SEvan.Yan@Sun.COM 
182110923SEvan.Yan@Sun.COM 	(void) pcicfg_config_teardown(&handle);
182210923SEvan.Yan@Sun.COM 
182310923SEvan.Yan@Sun.COM 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
182410923SEvan.Yan@Sun.COM 
182510923SEvan.Yan@Sun.COM 		if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) {
182610923SEvan.Yan@Sun.COM 			DEBUG0("Not enough memory to hotplug\n");
182710923SEvan.Yan@Sun.COM 			(void) pcicfg_destroy_phdl(dip);
182810923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
182910923SEvan.Yan@Sun.COM 		}
183010923SEvan.Yan@Sun.COM 
183110923SEvan.Yan@Sun.COM 		phdl = pcicfg_find_phdl(dip);
183210923SEvan.Yan@Sun.COM 		ASSERT(phdl);
183310923SEvan.Yan@Sun.COM 
183410923SEvan.Yan@Sun.COM 		(void) pcicfg_bridge_assign(dip, (void *)phdl);
183510923SEvan.Yan@Sun.COM 
183610923SEvan.Yan@Sun.COM 		if (phdl->error != PCICFG_SUCCESS) {
183710923SEvan.Yan@Sun.COM 			DEBUG0("Problem assigning bridge\n");
183810923SEvan.Yan@Sun.COM 			(void) pcicfg_destroy_phdl(dip);
183910923SEvan.Yan@Sun.COM 			return (phdl->error);
184010923SEvan.Yan@Sun.COM 		}
184110923SEvan.Yan@Sun.COM 
184210923SEvan.Yan@Sun.COM 		/*
184310923SEvan.Yan@Sun.COM 		 * Successfully allocated and assigned
184410923SEvan.Yan@Sun.COM 		 * memory.  Set the memory and IO length
184510923SEvan.Yan@Sun.COM 		 * to zero so when the handle is freed up
184610923SEvan.Yan@Sun.COM 		 * it will not de-allocate assigned resources.
184710923SEvan.Yan@Sun.COM 		 */
184810923SEvan.Yan@Sun.COM 		entry = (pcicfg_phdl_t *)phdl;
184910923SEvan.Yan@Sun.COM 
185010923SEvan.Yan@Sun.COM 		entry->memory_len = entry->io_len = 0;
185110923SEvan.Yan@Sun.COM 
185210923SEvan.Yan@Sun.COM 		/*
185310923SEvan.Yan@Sun.COM 		 * Free up the "entry" structure.
185410923SEvan.Yan@Sun.COM 		 */
185510923SEvan.Yan@Sun.COM 		(void) pcicfg_destroy_phdl(dip);
185610923SEvan.Yan@Sun.COM 	} else {
185710923SEvan.Yan@Sun.COM 		if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) {
185810923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
185910923SEvan.Yan@Sun.COM 		}
186010923SEvan.Yan@Sun.COM 	}
186110923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
186210923SEvan.Yan@Sun.COM }
186310923SEvan.Yan@Sun.COM 
186410923SEvan.Yan@Sun.COM static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)186510923SEvan.Yan@Sun.COM pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
186610923SEvan.Yan@Sun.COM {
186710923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
186810923SEvan.Yan@Sun.COM 	pci_regspec_t *reg;
186910923SEvan.Yan@Sun.COM 	int length;
187010923SEvan.Yan@Sun.COM 	int rcount;
187110923SEvan.Yan@Sun.COM 	int i;
187210923SEvan.Yan@Sun.COM 	int offset;
187310923SEvan.Yan@Sun.COM 	uint64_t mem_answer;
187410923SEvan.Yan@Sun.COM 	uint32_t io_answer;
187510923SEvan.Yan@Sun.COM 	int count;
187610923SEvan.Yan@Sun.COM 	uint8_t header_type;
187710923SEvan.Yan@Sun.COM 	pcicfg_range_t range[PCICFG_RANGE_LEN];
187810923SEvan.Yan@Sun.COM 	int bus_range[2];
187910923SEvan.Yan@Sun.COM 
188010923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
188110923SEvan.Yan@Sun.COM 
188210923SEvan.Yan@Sun.COM 	DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
188310923SEvan.Yan@Sun.COM 
188410923SEvan.Yan@Sun.COM 	if (entry == NULL) {
188510923SEvan.Yan@Sun.COM 		DEBUG0("Failed to get entry\n");
188610923SEvan.Yan@Sun.COM 		return (DDI_WALK_TERMINATE);
188710923SEvan.Yan@Sun.COM 	}
188810923SEvan.Yan@Sun.COM 
188910923SEvan.Yan@Sun.COM 	entry->error = PCICFG_SUCCESS;
189010923SEvan.Yan@Sun.COM 
189110923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
189210923SEvan.Yan@Sun.COM 		DEBUG0("Failed to map config space!\n");
189310923SEvan.Yan@Sun.COM 		entry->error = PCICFG_FAILURE;
189410923SEvan.Yan@Sun.COM 		return (DDI_WALK_TERMINATE);
189510923SEvan.Yan@Sun.COM 	}
189610923SEvan.Yan@Sun.COM 
189710923SEvan.Yan@Sun.COM 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
189810923SEvan.Yan@Sun.COM 
189910923SEvan.Yan@Sun.COM 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
190010923SEvan.Yan@Sun.COM 
190110923SEvan.Yan@Sun.COM 		bzero((caddr_t)range,
190210923SEvan.Yan@Sun.COM 		    sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
190310923SEvan.Yan@Sun.COM 
190410923SEvan.Yan@Sun.COM 		(void) pcicfg_setup_bridge(entry, handle, dip);
190510923SEvan.Yan@Sun.COM 
190610923SEvan.Yan@Sun.COM 		range[0].child_hi = range[0].parent_hi |=
190710923SEvan.Yan@Sun.COM 		    (PCI_REG_REL_M | PCI_ADDR_IO);
190810923SEvan.Yan@Sun.COM 		range[0].child_lo = range[0].parent_lo =
190910923SEvan.Yan@Sun.COM 		    entry->io_last;
191010923SEvan.Yan@Sun.COM 		range[1].child_hi = range[1].parent_hi |=
191110923SEvan.Yan@Sun.COM 		    (PCI_REG_REL_M | PCI_ADDR_MEM32);
191210923SEvan.Yan@Sun.COM 		range[1].child_lo = range[1].parent_lo =
191310923SEvan.Yan@Sun.COM 		    entry->memory_last;
191410923SEvan.Yan@Sun.COM 
191510923SEvan.Yan@Sun.COM 		ndi_devi_enter(dip, &count);
191610923SEvan.Yan@Sun.COM 		ddi_walk_devs(ddi_get_child(dip),
191710923SEvan.Yan@Sun.COM 		    pcicfg_bridge_assign, (void *)entry);
191810923SEvan.Yan@Sun.COM 		ndi_devi_exit(dip, count);
191910923SEvan.Yan@Sun.COM 
192010923SEvan.Yan@Sun.COM 		(void) pcicfg_update_bridge(entry, handle);
192110923SEvan.Yan@Sun.COM 
192210923SEvan.Yan@Sun.COM 		bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
192310923SEvan.Yan@Sun.COM 		bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
192410923SEvan.Yan@Sun.COM 
192510923SEvan.Yan@Sun.COM 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
192610923SEvan.Yan@Sun.COM 		    "bus-range", bus_range, 2) != DDI_SUCCESS) {
192710923SEvan.Yan@Sun.COM 			DEBUG0("Failed to set bus-range property");
192810923SEvan.Yan@Sun.COM 			entry->error = PCICFG_FAILURE;
192910923SEvan.Yan@Sun.COM 			return (DDI_WALK_TERMINATE);
193010923SEvan.Yan@Sun.COM 		}
193110923SEvan.Yan@Sun.COM 
193210923SEvan.Yan@Sun.COM 		if (entry->io_len > 0) {
193310923SEvan.Yan@Sun.COM 			range[0].size_lo = entry->io_last - entry->io_base;
193410923SEvan.Yan@Sun.COM 			if (pcicfg_update_ranges_prop(dip, &range[0])) {
193510923SEvan.Yan@Sun.COM 				DEBUG0("Failed to update ranges (i/o)\n");
193610923SEvan.Yan@Sun.COM 				entry->error = PCICFG_FAILURE;
193710923SEvan.Yan@Sun.COM 				return (DDI_WALK_TERMINATE);
193810923SEvan.Yan@Sun.COM 			}
193910923SEvan.Yan@Sun.COM 		}
194010923SEvan.Yan@Sun.COM 		if (entry->memory_len > 0) {
194110923SEvan.Yan@Sun.COM 			range[1].size_lo =
194210923SEvan.Yan@Sun.COM 			    entry->memory_last - entry->memory_base;
194310923SEvan.Yan@Sun.COM 			if (pcicfg_update_ranges_prop(dip, &range[1])) {
194410923SEvan.Yan@Sun.COM 				DEBUG0("Failed to update ranges (memory)\n");
194510923SEvan.Yan@Sun.COM 				entry->error = PCICFG_FAILURE;
194610923SEvan.Yan@Sun.COM 				return (DDI_WALK_TERMINATE);
194710923SEvan.Yan@Sun.COM 			}
194810923SEvan.Yan@Sun.COM 		}
194910923SEvan.Yan@Sun.COM 
195010923SEvan.Yan@Sun.COM 		(void) pcicfg_device_on(handle);
195110923SEvan.Yan@Sun.COM 
195210923SEvan.Yan@Sun.COM 		PCICFG_DUMP_BRIDGE_CONFIG(handle);
195310923SEvan.Yan@Sun.COM 
195410923SEvan.Yan@Sun.COM 		return (DDI_WALK_PRUNECHILD);
195510923SEvan.Yan@Sun.COM 	}
195610923SEvan.Yan@Sun.COM 
195710923SEvan.Yan@Sun.COM 	/*
195810923SEvan.Yan@Sun.COM 	 * If there is an interrupt pin set program
195910923SEvan.Yan@Sun.COM 	 * interrupt line with default values.
196010923SEvan.Yan@Sun.COM 	 */
196110923SEvan.Yan@Sun.COM 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
196210923SEvan.Yan@Sun.COM 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
196310923SEvan.Yan@Sun.COM 	}
196410923SEvan.Yan@Sun.COM 
196510923SEvan.Yan@Sun.COM 	/*
196610923SEvan.Yan@Sun.COM 	 * A single device (under a bridge).
196710923SEvan.Yan@Sun.COM 	 * For each "reg" property with a length, allocate memory
196810923SEvan.Yan@Sun.COM 	 * and program the base registers.
196910923SEvan.Yan@Sun.COM 	 */
197010923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
197110923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
197210923SEvan.Yan@Sun.COM 	    &length) != DDI_PROP_SUCCESS) {
197310923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read reg property\n");
197410923SEvan.Yan@Sun.COM 		entry->error = PCICFG_FAILURE;
197510923SEvan.Yan@Sun.COM 		return (DDI_WALK_TERMINATE);
197610923SEvan.Yan@Sun.COM 	}
197710923SEvan.Yan@Sun.COM 
197810923SEvan.Yan@Sun.COM 	rcount = length / sizeof (pci_regspec_t);
197910923SEvan.Yan@Sun.COM 	offset = PCI_CONF_BASE0;
198010923SEvan.Yan@Sun.COM 	for (i = 0; i < rcount; i++) {
198110923SEvan.Yan@Sun.COM 		if ((reg[i].pci_size_low != 0)||
198210923SEvan.Yan@Sun.COM 		    (reg[i].pci_size_hi != 0)) {
198310923SEvan.Yan@Sun.COM 
198410923SEvan.Yan@Sun.COM 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
198510923SEvan.Yan@Sun.COM 
198610923SEvan.Yan@Sun.COM 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
198710923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
198810923SEvan.Yan@Sun.COM 
198910923SEvan.Yan@Sun.COM 				(void) pcicfg_get_mem(entry,
199010923SEvan.Yan@Sun.COM 				    reg[i].pci_size_low, &mem_answer);
199110923SEvan.Yan@Sun.COM 				pci_config_put64(handle, offset, mem_answer);
199210923SEvan.Yan@Sun.COM 				DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
199310923SEvan.Yan@Sun.COM 				    offset,
199410923SEvan.Yan@Sun.COM 				    pci_config_get32(handle, offset));
199510923SEvan.Yan@Sun.COM 				DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
199610923SEvan.Yan@Sun.COM 				    offset + 4,
199710923SEvan.Yan@Sun.COM 				    pci_config_get32(handle, offset + 4));
199810923SEvan.Yan@Sun.COM 
199910923SEvan.Yan@Sun.COM 				reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer);
200010923SEvan.Yan@Sun.COM 				reg[i].pci_phys_mid  =
200110923SEvan.Yan@Sun.COM 				    PCICFG_LOADDR(mem_answer);
200210923SEvan.Yan@Sun.COM 
200310923SEvan.Yan@Sun.COM 				break;
200410923SEvan.Yan@Sun.COM 
200510923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
200610923SEvan.Yan@Sun.COM 				/* allocate memory space from the allocator */
200710923SEvan.Yan@Sun.COM 
200810923SEvan.Yan@Sun.COM 				(void) pcicfg_get_mem(entry,
200910923SEvan.Yan@Sun.COM 				    reg[i].pci_size_low, &mem_answer);
201010923SEvan.Yan@Sun.COM 				pci_config_put32(handle,
201110923SEvan.Yan@Sun.COM 				    offset, (uint32_t)mem_answer);
201210923SEvan.Yan@Sun.COM 
201310923SEvan.Yan@Sun.COM 				DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
201410923SEvan.Yan@Sun.COM 				    offset,
201510923SEvan.Yan@Sun.COM 				    pci_config_get32(handle, offset));
201610923SEvan.Yan@Sun.COM 
201710923SEvan.Yan@Sun.COM 				reg[i].pci_phys_low = (uint32_t)mem_answer;
201810923SEvan.Yan@Sun.COM 
201910923SEvan.Yan@Sun.COM 				break;
202010923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
202110923SEvan.Yan@Sun.COM 				/* allocate I/O space from the allocator */
202210923SEvan.Yan@Sun.COM 
202310923SEvan.Yan@Sun.COM 				(void) pcicfg_get_io(entry,
202410923SEvan.Yan@Sun.COM 				    reg[i].pci_size_low, &io_answer);
202510923SEvan.Yan@Sun.COM 				pci_config_put32(handle, offset, io_answer);
202610923SEvan.Yan@Sun.COM 
202710923SEvan.Yan@Sun.COM 				DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
202810923SEvan.Yan@Sun.COM 				    offset,
202910923SEvan.Yan@Sun.COM 				    pci_config_get32(handle, offset));
203010923SEvan.Yan@Sun.COM 
203110923SEvan.Yan@Sun.COM 				reg[i].pci_phys_low = io_answer;
203210923SEvan.Yan@Sun.COM 
203310923SEvan.Yan@Sun.COM 				break;
203410923SEvan.Yan@Sun.COM 			default:
203510923SEvan.Yan@Sun.COM 				DEBUG0("Unknown register type\n");
203610923SEvan.Yan@Sun.COM 				kmem_free(reg, length);
203710923SEvan.Yan@Sun.COM 				(void) pcicfg_config_teardown(&handle);
203810923SEvan.Yan@Sun.COM 				entry->error = PCICFG_FAILURE;
203910923SEvan.Yan@Sun.COM 				return (DDI_WALK_TERMINATE);
204010923SEvan.Yan@Sun.COM 			} /* switch */
204110923SEvan.Yan@Sun.COM 
204210923SEvan.Yan@Sun.COM 			/*
204310923SEvan.Yan@Sun.COM 			 * Now that memory locations are assigned,
204410923SEvan.Yan@Sun.COM 			 * update the assigned address property.
204510923SEvan.Yan@Sun.COM 			 */
204610923SEvan.Yan@Sun.COM 			if (pcicfg_update_assigned_prop(dip,
204710923SEvan.Yan@Sun.COM 			    &reg[i]) != PCICFG_SUCCESS) {
204810923SEvan.Yan@Sun.COM 				kmem_free(reg, length);
204910923SEvan.Yan@Sun.COM 				(void) pcicfg_config_teardown(&handle);
205010923SEvan.Yan@Sun.COM 				entry->error = PCICFG_FAILURE;
205110923SEvan.Yan@Sun.COM 				return (DDI_WALK_TERMINATE);
205210923SEvan.Yan@Sun.COM 			}
205310923SEvan.Yan@Sun.COM 		}
205410923SEvan.Yan@Sun.COM 	}
205510923SEvan.Yan@Sun.COM 	(void) pcicfg_device_on(handle);
205610923SEvan.Yan@Sun.COM 
205710923SEvan.Yan@Sun.COM 	PCICFG_DUMP_DEVICE_CONFIG(handle);
205810923SEvan.Yan@Sun.COM 
205910923SEvan.Yan@Sun.COM 	(void) pcicfg_config_teardown(&handle);
206010923SEvan.Yan@Sun.COM 	/*
206110923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
206210923SEvan.Yan@Sun.COM 	 */
206310923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)reg, length);
206410923SEvan.Yan@Sun.COM 
206510923SEvan.Yan@Sun.COM 	return (DDI_WALK_CONTINUE);
206610923SEvan.Yan@Sun.COM }
206710923SEvan.Yan@Sun.COM 
206810923SEvan.Yan@Sun.COM static int
pcicfg_device_assign(dev_info_t * dip)206910923SEvan.Yan@Sun.COM pcicfg_device_assign(dev_info_t *dip)
207010923SEvan.Yan@Sun.COM {
207110923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	handle;
207210923SEvan.Yan@Sun.COM 	pci_regspec_t		*reg;
207310923SEvan.Yan@Sun.COM 	int			length;
207410923SEvan.Yan@Sun.COM 	int			rcount;
207510923SEvan.Yan@Sun.COM 	int			i;
207610923SEvan.Yan@Sun.COM 	int			offset;
207710923SEvan.Yan@Sun.COM 	ndi_ra_request_t	request;
207810923SEvan.Yan@Sun.COM 	uint64_t		answer;
207910923SEvan.Yan@Sun.COM 	uint64_t		alen;
208010923SEvan.Yan@Sun.COM 
208110923SEvan.Yan@Sun.COM 	DEBUG1("%llx now under configuration\n", dip);
208210923SEvan.Yan@Sun.COM 
208310923SEvan.Yan@Sun.COM 	/*
208410923SEvan.Yan@Sun.COM 	 * XXX Failure here should be noted
208510923SEvan.Yan@Sun.COM 	 */
208610923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
208710923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
208810923SEvan.Yan@Sun.COM 	    &length) != DDI_PROP_SUCCESS) {
208910923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read reg property\n");
209010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
209110923SEvan.Yan@Sun.COM 	}
209210923SEvan.Yan@Sun.COM 
209310923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
209410923SEvan.Yan@Sun.COM 		DEBUG0("Failed to map config space!\n");
209510923SEvan.Yan@Sun.COM 		/*
209610923SEvan.Yan@Sun.COM 		 * Don't forget to free up memory from ddi_getlongprop
209710923SEvan.Yan@Sun.COM 		 */
209810923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)reg, length);
209910923SEvan.Yan@Sun.COM 
210010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
210110923SEvan.Yan@Sun.COM 	}
210210923SEvan.Yan@Sun.COM 
210310923SEvan.Yan@Sun.COM 	/*
210410923SEvan.Yan@Sun.COM 	 * A single device
210510923SEvan.Yan@Sun.COM 	 *
210610923SEvan.Yan@Sun.COM 	 * For each "reg" property with a length, allocate memory
210710923SEvan.Yan@Sun.COM 	 * and program the base registers.
210810923SEvan.Yan@Sun.COM 	 */
210910923SEvan.Yan@Sun.COM 
211010923SEvan.Yan@Sun.COM 	/*
211110923SEvan.Yan@Sun.COM 	 * If there is an interrupt pin set program
211210923SEvan.Yan@Sun.COM 	 * interrupt line with default values.
211310923SEvan.Yan@Sun.COM 	 */
211410923SEvan.Yan@Sun.COM 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
211510923SEvan.Yan@Sun.COM 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
211610923SEvan.Yan@Sun.COM 	}
211710923SEvan.Yan@Sun.COM 
211810923SEvan.Yan@Sun.COM 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
211910923SEvan.Yan@Sun.COM 
2120*12765SScott.Carter@Oracle.COM 	request.ra_flags = NDI_RA_ALIGN_SIZE;
212110923SEvan.Yan@Sun.COM 	request.ra_boundbase = 0;
212210923SEvan.Yan@Sun.COM 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
212310923SEvan.Yan@Sun.COM 
212410923SEvan.Yan@Sun.COM 	rcount = length / sizeof (pci_regspec_t);
212510923SEvan.Yan@Sun.COM 	for (i = 0; i < rcount; i++) {
212610923SEvan.Yan@Sun.COM 		if ((reg[i].pci_size_low != 0)||
212710923SEvan.Yan@Sun.COM 		    (reg[i].pci_size_hi != 0)) {
212810923SEvan.Yan@Sun.COM 
212910923SEvan.Yan@Sun.COM 			offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
213010923SEvan.Yan@Sun.COM 			request.ra_len = reg[i].pci_size_low;
213110923SEvan.Yan@Sun.COM 
213210923SEvan.Yan@Sun.COM 			switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
213310923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2134*12765SScott.Carter@Oracle.COM 				request.ra_flags &= ~NDI_RA_ALLOC_BOUNDED;
213510923SEvan.Yan@Sun.COM 				/* allocate memory space from the allocator */
213610923SEvan.Yan@Sun.COM 				if (ndi_ra_alloc(ddi_get_parent(dip),
213710923SEvan.Yan@Sun.COM 				    &request, &answer, &alen,
213810923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
213910923SEvan.Yan@Sun.COM 				    != NDI_SUCCESS) {
214010923SEvan.Yan@Sun.COM 					DEBUG0("Failed to allocate 64b mem\n");
214110923SEvan.Yan@Sun.COM 					kmem_free(reg, length);
214210923SEvan.Yan@Sun.COM 					(void) pcicfg_config_teardown(&handle);
214310923SEvan.Yan@Sun.COM 					return (PCICFG_FAILURE);
214410923SEvan.Yan@Sun.COM 				}
214510923SEvan.Yan@Sun.COM 				DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
214610923SEvan.Yan@Sun.COM 				    PCICFG_HIADDR(answer),
214710923SEvan.Yan@Sun.COM 				    PCICFG_LOADDR(answer),
214810923SEvan.Yan@Sun.COM 				    alen);
214910923SEvan.Yan@Sun.COM 				/* program the low word */
215010923SEvan.Yan@Sun.COM 				pci_config_put32(handle,
215110923SEvan.Yan@Sun.COM 				    offset, PCICFG_LOADDR(answer));
215210923SEvan.Yan@Sun.COM 
2153*12765SScott.Carter@Oracle.COM 				/* program the high word */
215410923SEvan.Yan@Sun.COM 				pci_config_put32(handle, offset + 4,
215510923SEvan.Yan@Sun.COM 				    PCICFG_HIADDR(answer));
215610923SEvan.Yan@Sun.COM 
215710923SEvan.Yan@Sun.COM 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
215810923SEvan.Yan@Sun.COM 				reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
2159*12765SScott.Carter@Oracle.COM 
2160*12765SScott.Carter@Oracle.COM 				/* adjust to 32b address space when possible */
2161*12765SScott.Carter@Oracle.COM 				if ((answer + alen) <= PCICFG_4GIG_LIMIT)
2162*12765SScott.Carter@Oracle.COM 					reg[i].pci_phys_hi ^=
2163*12765SScott.Carter@Oracle.COM 					    PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
216410923SEvan.Yan@Sun.COM 				break;
216510923SEvan.Yan@Sun.COM 
216610923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
216710923SEvan.Yan@Sun.COM 				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
216810923SEvan.Yan@Sun.COM 				/* allocate memory space from the allocator */
216910923SEvan.Yan@Sun.COM 				if (ndi_ra_alloc(ddi_get_parent(dip),
217010923SEvan.Yan@Sun.COM 				    &request, &answer, &alen,
217110923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
217210923SEvan.Yan@Sun.COM 				    != NDI_SUCCESS) {
217310923SEvan.Yan@Sun.COM 					DEBUG0("Failed to allocate 32b mem\n");
217410923SEvan.Yan@Sun.COM 					kmem_free(reg, length);
217510923SEvan.Yan@Sun.COM 					(void) pcicfg_config_teardown(&handle);
217610923SEvan.Yan@Sun.COM 					return (PCICFG_FAILURE);
217710923SEvan.Yan@Sun.COM 				}
217810923SEvan.Yan@Sun.COM 				DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
217910923SEvan.Yan@Sun.COM 				    PCICFG_HIADDR(answer),
218010923SEvan.Yan@Sun.COM 				    PCICFG_LOADDR(answer),
218110923SEvan.Yan@Sun.COM 				    alen);
218210923SEvan.Yan@Sun.COM 				/* program the low word */
218310923SEvan.Yan@Sun.COM 				pci_config_put32(handle,
218410923SEvan.Yan@Sun.COM 				    offset, PCICFG_LOADDR(answer));
218510923SEvan.Yan@Sun.COM 
218610923SEvan.Yan@Sun.COM 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
218710923SEvan.Yan@Sun.COM 				break;
2188*12765SScott.Carter@Oracle.COM 
218910923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
219010923SEvan.Yan@Sun.COM 				/* allocate I/O space from the allocator */
219110923SEvan.Yan@Sun.COM 				request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
219210923SEvan.Yan@Sun.COM 				if (ndi_ra_alloc(ddi_get_parent(dip),
219310923SEvan.Yan@Sun.COM 				    &request, &answer, &alen,
219410923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
219510923SEvan.Yan@Sun.COM 				    != NDI_SUCCESS) {
219610923SEvan.Yan@Sun.COM 					DEBUG0("Failed to allocate I/O\n");
219710923SEvan.Yan@Sun.COM 					kmem_free(reg, length);
219810923SEvan.Yan@Sun.COM 					(void) pcicfg_config_teardown(&handle);
219910923SEvan.Yan@Sun.COM 					return (PCICFG_FAILURE);
220010923SEvan.Yan@Sun.COM 				}
220110923SEvan.Yan@Sun.COM 				DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
220210923SEvan.Yan@Sun.COM 				    PCICFG_HIADDR(answer),
220310923SEvan.Yan@Sun.COM 				    PCICFG_LOADDR(answer),
220410923SEvan.Yan@Sun.COM 				    alen);
220510923SEvan.Yan@Sun.COM 				pci_config_put32(handle,
220610923SEvan.Yan@Sun.COM 				    offset, PCICFG_LOADDR(answer));
220710923SEvan.Yan@Sun.COM 
220810923SEvan.Yan@Sun.COM 				reg[i].pci_phys_low = PCICFG_LOADDR(answer);
220910923SEvan.Yan@Sun.COM 				break;
2210*12765SScott.Carter@Oracle.COM 
221110923SEvan.Yan@Sun.COM 			default:
221210923SEvan.Yan@Sun.COM 				DEBUG0("Unknown register type\n");
221310923SEvan.Yan@Sun.COM 				kmem_free(reg, length);
221410923SEvan.Yan@Sun.COM 				(void) pcicfg_config_teardown(&handle);
221510923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
221610923SEvan.Yan@Sun.COM 			} /* switch */
221710923SEvan.Yan@Sun.COM 
221810923SEvan.Yan@Sun.COM 			/*
221910923SEvan.Yan@Sun.COM 			 * Now that memory locations are assigned,
222010923SEvan.Yan@Sun.COM 			 * update the assigned address property.
222110923SEvan.Yan@Sun.COM 			 */
222210923SEvan.Yan@Sun.COM 
222310923SEvan.Yan@Sun.COM 			if (pcicfg_update_assigned_prop(dip,
222410923SEvan.Yan@Sun.COM 			    &reg[i]) != PCICFG_SUCCESS) {
222510923SEvan.Yan@Sun.COM 				kmem_free(reg, length);
222610923SEvan.Yan@Sun.COM 				(void) pcicfg_config_teardown(&handle);
222710923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
222810923SEvan.Yan@Sun.COM 			}
222910923SEvan.Yan@Sun.COM 		}
223010923SEvan.Yan@Sun.COM 	}
223110923SEvan.Yan@Sun.COM 
223210923SEvan.Yan@Sun.COM 	(void) pcicfg_device_on(handle);
223310923SEvan.Yan@Sun.COM 	kmem_free(reg, length);
223410923SEvan.Yan@Sun.COM 
223510923SEvan.Yan@Sun.COM 	PCICFG_DUMP_DEVICE_CONFIG(handle);
223610923SEvan.Yan@Sun.COM 
223710923SEvan.Yan@Sun.COM 	(void) pcicfg_config_teardown(&handle);
223810923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
223910923SEvan.Yan@Sun.COM }
224010923SEvan.Yan@Sun.COM 
224110923SEvan.Yan@Sun.COM static int
pcicfg_device_assign_readonly(dev_info_t * dip)224210923SEvan.Yan@Sun.COM pcicfg_device_assign_readonly(dev_info_t *dip)
224310923SEvan.Yan@Sun.COM {
224410923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	handle;
224510923SEvan.Yan@Sun.COM 	pci_regspec_t		*assigned;
224610923SEvan.Yan@Sun.COM 	int			length;
224710923SEvan.Yan@Sun.COM 	int			acount;
224810923SEvan.Yan@Sun.COM 	int			i;
224910923SEvan.Yan@Sun.COM 	ndi_ra_request_t	request;
225010923SEvan.Yan@Sun.COM 	uint64_t		answer;
225110923SEvan.Yan@Sun.COM 	uint64_t		alen;
225210923SEvan.Yan@Sun.COM 
225310923SEvan.Yan@Sun.COM 
225410923SEvan.Yan@Sun.COM 	DEBUG1("%llx now under configuration\n", dip);
225510923SEvan.Yan@Sun.COM 
225610923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
225710923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
225810923SEvan.Yan@Sun.COM 	    &length) != DDI_PROP_SUCCESS) {
225910923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read assigned-addresses property\n");
226010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
226110923SEvan.Yan@Sun.COM 	}
226210923SEvan.Yan@Sun.COM 
226310923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
226410923SEvan.Yan@Sun.COM 		DEBUG0("Failed to map config space!\n");
226510923SEvan.Yan@Sun.COM 		/*
226610923SEvan.Yan@Sun.COM 		 * Don't forget to free up memory from ddi_getlongprop
226710923SEvan.Yan@Sun.COM 		 */
226810923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)assigned, length);
226910923SEvan.Yan@Sun.COM 
227010923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
227110923SEvan.Yan@Sun.COM 	}
227210923SEvan.Yan@Sun.COM 
227310923SEvan.Yan@Sun.COM 	/*
227410923SEvan.Yan@Sun.COM 	 * For each "assigned-addresses" property entry with a length,
227510923SEvan.Yan@Sun.COM 	 * call the memory allocation routines to return the
227610923SEvan.Yan@Sun.COM 	 * resource.
227710923SEvan.Yan@Sun.COM 	 */
227810923SEvan.Yan@Sun.COM 	/*
227910923SEvan.Yan@Sun.COM 	 * If there is an interrupt pin set program
228010923SEvan.Yan@Sun.COM 	 * interrupt line with default values.
228110923SEvan.Yan@Sun.COM 	 */
228210923SEvan.Yan@Sun.COM 	if (pci_config_get8(handle, PCI_CONF_IPIN)) {
228310923SEvan.Yan@Sun.COM 		pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
228410923SEvan.Yan@Sun.COM 	}
228510923SEvan.Yan@Sun.COM 
228610923SEvan.Yan@Sun.COM 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
228710923SEvan.Yan@Sun.COM 
228810923SEvan.Yan@Sun.COM 	request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */
228910923SEvan.Yan@Sun.COM 	request.ra_boundbase = 0;
229010923SEvan.Yan@Sun.COM 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
229110923SEvan.Yan@Sun.COM 
229210923SEvan.Yan@Sun.COM 	acount = length / sizeof (pci_regspec_t);
229310923SEvan.Yan@Sun.COM 	for (i = 0; i < acount; i++) {
229410923SEvan.Yan@Sun.COM 		if ((assigned[i].pci_size_low != 0)||
229510923SEvan.Yan@Sun.COM 		    (assigned[i].pci_size_hi != 0)) {
229610923SEvan.Yan@Sun.COM 
229710923SEvan.Yan@Sun.COM 			request.ra_len = assigned[i].pci_size_low;
229810923SEvan.Yan@Sun.COM 
229910923SEvan.Yan@Sun.COM 			switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
230010923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
230110923SEvan.Yan@Sun.COM 				request.ra_addr = (uint64_t)PCICFG_LADDR(
230210923SEvan.Yan@Sun.COM 				    assigned[i].pci_phys_low,
230310923SEvan.Yan@Sun.COM 				    assigned[i].pci_phys_mid);
230410923SEvan.Yan@Sun.COM 
230510923SEvan.Yan@Sun.COM 				/* allocate memory space from the allocator */
230610923SEvan.Yan@Sun.COM 				if (ndi_ra_alloc(ddi_get_parent(dip),
230710923SEvan.Yan@Sun.COM 				    &request, &answer, &alen,
230810923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
230910923SEvan.Yan@Sun.COM 				    != NDI_SUCCESS) {
231010923SEvan.Yan@Sun.COM 					DEBUG0("Failed to allocate 64b mem\n");
231110923SEvan.Yan@Sun.COM 					kmem_free(assigned, length);
231210923SEvan.Yan@Sun.COM 					return (PCICFG_FAILURE);
231310923SEvan.Yan@Sun.COM 				}
231410923SEvan.Yan@Sun.COM 
231510923SEvan.Yan@Sun.COM 				break;
231610923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
231710923SEvan.Yan@Sun.COM 				request.ra_addr = (uint64_t)
231810923SEvan.Yan@Sun.COM 				    assigned[i].pci_phys_low;
231910923SEvan.Yan@Sun.COM 
232010923SEvan.Yan@Sun.COM 				/* allocate memory space from the allocator */
232110923SEvan.Yan@Sun.COM 				if (ndi_ra_alloc(ddi_get_parent(dip),
232210923SEvan.Yan@Sun.COM 				    &request, &answer, &alen,
232310923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_MEM, NDI_RA_PASS)
232410923SEvan.Yan@Sun.COM 				    != NDI_SUCCESS) {
232510923SEvan.Yan@Sun.COM 					DEBUG0("Failed to allocate 32b mem\n");
232610923SEvan.Yan@Sun.COM 					kmem_free(assigned, length);
232710923SEvan.Yan@Sun.COM 					return (PCICFG_FAILURE);
232810923SEvan.Yan@Sun.COM 				}
232910923SEvan.Yan@Sun.COM 
233010923SEvan.Yan@Sun.COM 				break;
233110923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
233210923SEvan.Yan@Sun.COM 				request.ra_addr = (uint64_t)
233310923SEvan.Yan@Sun.COM 				    assigned[i].pci_phys_low;
233410923SEvan.Yan@Sun.COM 
233510923SEvan.Yan@Sun.COM 				/* allocate I/O space from the allocator */
233610923SEvan.Yan@Sun.COM 				if (ndi_ra_alloc(ddi_get_parent(dip),
233710923SEvan.Yan@Sun.COM 				    &request, &answer, &alen,
233810923SEvan.Yan@Sun.COM 				    NDI_RA_TYPE_IO, NDI_RA_PASS)
233910923SEvan.Yan@Sun.COM 				    != NDI_SUCCESS) {
234010923SEvan.Yan@Sun.COM 					DEBUG0("Failed to allocate I/O\n");
234110923SEvan.Yan@Sun.COM 					kmem_free(assigned, length);
234210923SEvan.Yan@Sun.COM 					return (PCICFG_FAILURE);
234310923SEvan.Yan@Sun.COM 				}
234410923SEvan.Yan@Sun.COM 
234510923SEvan.Yan@Sun.COM 				break;
234610923SEvan.Yan@Sun.COM 			default:
234710923SEvan.Yan@Sun.COM 				DEBUG0("Unknown register type\n");
234810923SEvan.Yan@Sun.COM 				kmem_free(assigned, length);
234910923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
235010923SEvan.Yan@Sun.COM 			} /* switch */
235110923SEvan.Yan@Sun.COM 		}
235210923SEvan.Yan@Sun.COM 	}
235310923SEvan.Yan@Sun.COM 
235410923SEvan.Yan@Sun.COM 	(void) pcicfg_device_on(handle);
235510923SEvan.Yan@Sun.COM 	kmem_free(assigned, length);
235610923SEvan.Yan@Sun.COM 
235710923SEvan.Yan@Sun.COM 	PCICFG_DUMP_DEVICE_CONFIG(handle);
235810923SEvan.Yan@Sun.COM 
235910923SEvan.Yan@Sun.COM 	(void) pcicfg_config_teardown(&handle);
236010923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
236110923SEvan.Yan@Sun.COM }
236210923SEvan.Yan@Sun.COM 
236310923SEvan.Yan@Sun.COM /*
236410923SEvan.Yan@Sun.COM  * The "dip" passed to this routine is assumed to be
236510923SEvan.Yan@Sun.COM  * the device at the Hotplug Connection (CN). Currently it is
236610923SEvan.Yan@Sun.COM  * assumed to be a bridge.
236710923SEvan.Yan@Sun.COM  */
236810923SEvan.Yan@Sun.COM static int
pcicfg_allocate_chunk(dev_info_t * dip)236910923SEvan.Yan@Sun.COM pcicfg_allocate_chunk(dev_info_t *dip)
237010923SEvan.Yan@Sun.COM {
237110923SEvan.Yan@Sun.COM 	pcicfg_phdl_t		*phdl;
237210923SEvan.Yan@Sun.COM 	ndi_ra_request_t	*mem_request;
237310923SEvan.Yan@Sun.COM 	ndi_ra_request_t	*io_request;
237410923SEvan.Yan@Sun.COM 	uint64_t		mem_answer;
237510923SEvan.Yan@Sun.COM 	uint64_t		io_answer;
237610923SEvan.Yan@Sun.COM 	int			count;
237710923SEvan.Yan@Sun.COM 	uint64_t		alen;
237810923SEvan.Yan@Sun.COM 
237910923SEvan.Yan@Sun.COM 	/*
238010923SEvan.Yan@Sun.COM 	 * This should not find an existing entry - so
238110923SEvan.Yan@Sun.COM 	 * it will create a new one.
238210923SEvan.Yan@Sun.COM 	 */
238310923SEvan.Yan@Sun.COM 	phdl = pcicfg_find_phdl(dip);
238410923SEvan.Yan@Sun.COM 	ASSERT(phdl);
238510923SEvan.Yan@Sun.COM 
238610923SEvan.Yan@Sun.COM 	mem_request = &phdl->mem_req;
238710923SEvan.Yan@Sun.COM 	io_request  = &phdl->io_req;
238810923SEvan.Yan@Sun.COM 
238910923SEvan.Yan@Sun.COM 	/*
239010923SEvan.Yan@Sun.COM 	 * From this point in the tree - walk the devices,
239110923SEvan.Yan@Sun.COM 	 * The function passed in will read and "sum" up
239210923SEvan.Yan@Sun.COM 	 * the memory and I/O requirements and put them in
239310923SEvan.Yan@Sun.COM 	 * structure "phdl".
239410923SEvan.Yan@Sun.COM 	 */
239510923SEvan.Yan@Sun.COM 	ndi_devi_enter(ddi_get_parent(dip), &count);
239610923SEvan.Yan@Sun.COM 	ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl);
239710923SEvan.Yan@Sun.COM 	ndi_devi_exit(ddi_get_parent(dip), count);
239810923SEvan.Yan@Sun.COM 
239910923SEvan.Yan@Sun.COM 	if (phdl->error != PCICFG_SUCCESS) {
240010923SEvan.Yan@Sun.COM 		DEBUG0("Failure summing resources\n");
240110923SEvan.Yan@Sun.COM 		return (phdl->error);
240210923SEvan.Yan@Sun.COM 	}
240310923SEvan.Yan@Sun.COM 
240410923SEvan.Yan@Sun.COM 	/*
240510923SEvan.Yan@Sun.COM 	 * Call into the memory allocator with the request.
240610923SEvan.Yan@Sun.COM 	 * Record the addresses returned in the phdl
240710923SEvan.Yan@Sun.COM 	 */
240810923SEvan.Yan@Sun.COM 	DEBUG1("Connector requires [0x%x] bytes of memory space\n",
240910923SEvan.Yan@Sun.COM 	    mem_request->ra_len);
241010923SEvan.Yan@Sun.COM 	DEBUG1("Connector requires [0x%x] bytes of I/O space\n",
241110923SEvan.Yan@Sun.COM 	    io_request->ra_len);
241210923SEvan.Yan@Sun.COM 
241310923SEvan.Yan@Sun.COM 	mem_request->ra_align_mask =
241410923SEvan.Yan@Sun.COM 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
241510923SEvan.Yan@Sun.COM 	io_request->ra_align_mask =
241610923SEvan.Yan@Sun.COM 	    PCICFG_IOGRAN - 1;   /* 4K alignment on I/O space */
241710923SEvan.Yan@Sun.COM 	io_request->ra_boundbase = 0;
241810923SEvan.Yan@Sun.COM 	io_request->ra_boundlen = PCICFG_4GIG_LIMIT;
241910923SEvan.Yan@Sun.COM 	io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
242010923SEvan.Yan@Sun.COM 
242110923SEvan.Yan@Sun.COM 	mem_request->ra_len =
242210923SEvan.Yan@Sun.COM 	    PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
242310923SEvan.Yan@Sun.COM 
242410923SEvan.Yan@Sun.COM 	io_request->ra_len =
242510923SEvan.Yan@Sun.COM 	    PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
242610923SEvan.Yan@Sun.COM 
242710923SEvan.Yan@Sun.COM 	if (ndi_ra_alloc(ddi_get_parent(dip),
242810923SEvan.Yan@Sun.COM 	    mem_request, &mem_answer, &alen,
242910923SEvan.Yan@Sun.COM 	    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
243010923SEvan.Yan@Sun.COM 		DEBUG0("Failed to allocate memory\n");
243110923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
243210923SEvan.Yan@Sun.COM 	}
243310923SEvan.Yan@Sun.COM 
243410923SEvan.Yan@Sun.COM 	phdl->memory_base = phdl->memory_last = mem_answer;
243510923SEvan.Yan@Sun.COM 	phdl->memory_len  = alen;
243610923SEvan.Yan@Sun.COM 
243710923SEvan.Yan@Sun.COM 	phdl->mem_hole.start = phdl->memory_base;
243810923SEvan.Yan@Sun.COM 	phdl->mem_hole.len = phdl->memory_len;
243910923SEvan.Yan@Sun.COM 	phdl->mem_hole.next = (hole_t *)NULL;
244010923SEvan.Yan@Sun.COM 
244110923SEvan.Yan@Sun.COM 	if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer,
244210923SEvan.Yan@Sun.COM 	    &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
244310923SEvan.Yan@Sun.COM 
244410923SEvan.Yan@Sun.COM 		DEBUG0("Failed to allocate I/O space\n");
244510923SEvan.Yan@Sun.COM 		(void) ndi_ra_free(ddi_get_parent(dip), mem_answer,
244610923SEvan.Yan@Sun.COM 		    alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
244710923SEvan.Yan@Sun.COM 		phdl->memory_len = phdl->io_len = 0;
244810923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
244910923SEvan.Yan@Sun.COM 	}
245010923SEvan.Yan@Sun.COM 
245110923SEvan.Yan@Sun.COM 	phdl->io_base = phdl->io_last = (uint32_t)io_answer;
245210923SEvan.Yan@Sun.COM 	phdl->io_len  = (uint32_t)alen;
245310923SEvan.Yan@Sun.COM 
245410923SEvan.Yan@Sun.COM 	phdl->io_hole.start = phdl->io_base;
245510923SEvan.Yan@Sun.COM 	phdl->io_hole.len = phdl->io_len;
245610923SEvan.Yan@Sun.COM 	phdl->io_hole.next = (hole_t *)NULL;
245710923SEvan.Yan@Sun.COM 
245810923SEvan.Yan@Sun.COM 	DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
245910923SEvan.Yan@Sun.COM 	    phdl->memory_base, phdl->memory_len);
246010923SEvan.Yan@Sun.COM 	DEBUG2("IO     BASE = [0x%x] length [0x%x]\n",
246110923SEvan.Yan@Sun.COM 	    phdl->io_base, phdl->io_len);
246210923SEvan.Yan@Sun.COM 
246310923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
246410923SEvan.Yan@Sun.COM }
246510923SEvan.Yan@Sun.COM 
246610923SEvan.Yan@Sun.COM #ifdef	DEBUG
246710923SEvan.Yan@Sun.COM /*
246810923SEvan.Yan@Sun.COM  * This function is useful in debug mode, where we can measure how
246910923SEvan.Yan@Sun.COM  * much memory was wasted/unallocated in bridge device's domain.
247010923SEvan.Yan@Sun.COM  */
247110923SEvan.Yan@Sun.COM static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)247210923SEvan.Yan@Sun.COM pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
247310923SEvan.Yan@Sun.COM {
247410923SEvan.Yan@Sun.COM 	uint64_t len = 0;
247510923SEvan.Yan@Sun.COM 	uint32_t count = 0;
247610923SEvan.Yan@Sun.COM 
247710923SEvan.Yan@Sun.COM 	do {
247810923SEvan.Yan@Sun.COM 		len += hole->len;
247910923SEvan.Yan@Sun.COM 		hole = hole->next;
248010923SEvan.Yan@Sun.COM 		count++;
248110923SEvan.Yan@Sun.COM 	} while (hole);
248210923SEvan.Yan@Sun.COM 	*hole_count = count;
248310923SEvan.Yan@Sun.COM 	return (len);
248410923SEvan.Yan@Sun.COM }
248510923SEvan.Yan@Sun.COM #endif
248610923SEvan.Yan@Sun.COM 
248710923SEvan.Yan@Sun.COM /*
248810923SEvan.Yan@Sun.COM  * This function frees data structures that hold the hole information
248910923SEvan.Yan@Sun.COM  * which are allocated in pcicfg_alloc_hole(). This is not freeing
249010923SEvan.Yan@Sun.COM  * any memory allocated through NDI calls.
249110923SEvan.Yan@Sun.COM  */
249210923SEvan.Yan@Sun.COM static void
pcicfg_free_hole(hole_t * addr_hole)249310923SEvan.Yan@Sun.COM pcicfg_free_hole(hole_t *addr_hole)
249410923SEvan.Yan@Sun.COM {
249510923SEvan.Yan@Sun.COM 	hole_t *nhole, *hole = addr_hole->next;
249610923SEvan.Yan@Sun.COM 
249710923SEvan.Yan@Sun.COM 	while (hole) {
249810923SEvan.Yan@Sun.COM 		nhole = hole->next;
249910923SEvan.Yan@Sun.COM 		kmem_free(hole, sizeof (hole_t));
250010923SEvan.Yan@Sun.COM 		hole = nhole;
250110923SEvan.Yan@Sun.COM 	}
250210923SEvan.Yan@Sun.COM }
250310923SEvan.Yan@Sun.COM 
250410923SEvan.Yan@Sun.COM static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)250510923SEvan.Yan@Sun.COM pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
250610923SEvan.Yan@Sun.COM {
250710923SEvan.Yan@Sun.COM 	uint64_t actual_hole_start, ostart, olen;
250810923SEvan.Yan@Sun.COM 	hole_t	*hole = addr_hole, *thole, *nhole;
250910923SEvan.Yan@Sun.COM 
251010923SEvan.Yan@Sun.COM 	do {
251110923SEvan.Yan@Sun.COM 		actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
251210923SEvan.Yan@Sun.COM 		if (((actual_hole_start - hole->start) + length) <= hole->len) {
251310923SEvan.Yan@Sun.COM 			DEBUG3("hole found. start %llx, len %llx, req=%x\n",
251410923SEvan.Yan@Sun.COM 			    hole->start, hole->len, length);
251510923SEvan.Yan@Sun.COM 			ostart = hole->start;
251610923SEvan.Yan@Sun.COM 			olen = hole->len;
251710923SEvan.Yan@Sun.COM 			/* current hole parameters adjust */
251810923SEvan.Yan@Sun.COM 			if ((actual_hole_start - hole->start) == 0) {
251910923SEvan.Yan@Sun.COM 				hole->start += length;
252010923SEvan.Yan@Sun.COM 				hole->len -= length;
252110923SEvan.Yan@Sun.COM 				if (hole->start > *alast)
252210923SEvan.Yan@Sun.COM 					*alast = hole->start;
252310923SEvan.Yan@Sun.COM 			} else {
252410923SEvan.Yan@Sun.COM 				hole->len = actual_hole_start - hole->start;
252510923SEvan.Yan@Sun.COM 				nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
252610923SEvan.Yan@Sun.COM 				    KM_SLEEP);
252710923SEvan.Yan@Sun.COM 				nhole->start = actual_hole_start + length;
252810923SEvan.Yan@Sun.COM 				nhole->len = (ostart + olen) - nhole->start;
252910923SEvan.Yan@Sun.COM 				nhole->next = NULL;
253010923SEvan.Yan@Sun.COM 				thole = hole->next;
253110923SEvan.Yan@Sun.COM 				hole->next = nhole;
253210923SEvan.Yan@Sun.COM 				nhole->next = thole;
253310923SEvan.Yan@Sun.COM 				if (nhole->start > *alast)
253410923SEvan.Yan@Sun.COM 					*alast = nhole->start;
253510923SEvan.Yan@Sun.COM 				DEBUG2("put new hole to %llx, %llx\n",
253610923SEvan.Yan@Sun.COM 				    nhole->start, nhole->len);
253710923SEvan.Yan@Sun.COM 			}
253810923SEvan.Yan@Sun.COM 			DEBUG2("adjust current hole to %llx, %llx\n",
253910923SEvan.Yan@Sun.COM 			    hole->start, hole->len);
254010923SEvan.Yan@Sun.COM 			break;
254110923SEvan.Yan@Sun.COM 		}
254210923SEvan.Yan@Sun.COM 		actual_hole_start = 0;
254310923SEvan.Yan@Sun.COM 		hole = hole->next;
254410923SEvan.Yan@Sun.COM 	} while (hole);
254510923SEvan.Yan@Sun.COM 
254610923SEvan.Yan@Sun.COM 	DEBUG1("return hole at %llx\n", actual_hole_start);
254710923SEvan.Yan@Sun.COM 	return (actual_hole_start);
254810923SEvan.Yan@Sun.COM }
254910923SEvan.Yan@Sun.COM 
255010923SEvan.Yan@Sun.COM static void
pcicfg_get_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)255110923SEvan.Yan@Sun.COM pcicfg_get_mem(pcicfg_phdl_t *entry,
255210923SEvan.Yan@Sun.COM 	uint32_t length, uint64_t *ans)
255310923SEvan.Yan@Sun.COM {
255410923SEvan.Yan@Sun.COM 	uint64_t new_mem;
255510923SEvan.Yan@Sun.COM 
255610923SEvan.Yan@Sun.COM 	/* See if there is a hole, that can hold this request. */
255710923SEvan.Yan@Sun.COM 	new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
255810923SEvan.Yan@Sun.COM 	    length);
255910923SEvan.Yan@Sun.COM 	if (new_mem) {	/* if non-zero, found a hole. */
256010923SEvan.Yan@Sun.COM 		if (ans != NULL)
256110923SEvan.Yan@Sun.COM 			*ans = new_mem;
256210923SEvan.Yan@Sun.COM 	} else
256310923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
256410923SEvan.Yan@Sun.COM 		    length, ddi_get_name(entry->dip));
256510923SEvan.Yan@Sun.COM }
256610923SEvan.Yan@Sun.COM 
256710923SEvan.Yan@Sun.COM static void
pcicfg_get_io(pcicfg_phdl_t * entry,uint32_t length,uint32_t * ans)256810923SEvan.Yan@Sun.COM pcicfg_get_io(pcicfg_phdl_t *entry,
256910923SEvan.Yan@Sun.COM 	uint32_t length, uint32_t *ans)
257010923SEvan.Yan@Sun.COM {
257110923SEvan.Yan@Sun.COM 	uint32_t new_io;
257210923SEvan.Yan@Sun.COM 	uint64_t io_last;
257310923SEvan.Yan@Sun.COM 
257410923SEvan.Yan@Sun.COM 	/*
257510923SEvan.Yan@Sun.COM 	 * See if there is a hole, that can hold this request.
257610923SEvan.Yan@Sun.COM 	 * Pass 64 bit parameters and then truncate to 32 bit.
257710923SEvan.Yan@Sun.COM 	 */
257810923SEvan.Yan@Sun.COM 	io_last = entry->io_last;
257910923SEvan.Yan@Sun.COM 	new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
258010923SEvan.Yan@Sun.COM 	if (new_io) {	/* if non-zero, found a hole. */
258110923SEvan.Yan@Sun.COM 		entry->io_last = (uint32_t)io_last;
258210923SEvan.Yan@Sun.COM 		if (ans != NULL)
258310923SEvan.Yan@Sun.COM 			*ans = new_io;
258410923SEvan.Yan@Sun.COM 	} else
258510923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
258610923SEvan.Yan@Sun.COM 		    length, ddi_get_name(entry->dip));
258710923SEvan.Yan@Sun.COM }
258810923SEvan.Yan@Sun.COM 
258910923SEvan.Yan@Sun.COM static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)259010923SEvan.Yan@Sun.COM pcicfg_sum_resources(dev_info_t *dip, void *hdl)
259110923SEvan.Yan@Sun.COM {
259210923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
259310923SEvan.Yan@Sun.COM 	pci_regspec_t *pci_rp;
259410923SEvan.Yan@Sun.COM 	int length;
259510923SEvan.Yan@Sun.COM 	int rcount;
259610923SEvan.Yan@Sun.COM 	int i;
259710923SEvan.Yan@Sun.COM 	ndi_ra_request_t *mem_request;
259810923SEvan.Yan@Sun.COM 	ndi_ra_request_t *io_request;
259910923SEvan.Yan@Sun.COM 	uint8_t header_type;
260010923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
260110923SEvan.Yan@Sun.COM 
260210923SEvan.Yan@Sun.COM 	entry->error = PCICFG_SUCCESS;
260310923SEvan.Yan@Sun.COM 
260410923SEvan.Yan@Sun.COM 	mem_request = &entry->mem_req;
260510923SEvan.Yan@Sun.COM 	io_request =  &entry->io_req;
260610923SEvan.Yan@Sun.COM 
260710923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
260810923SEvan.Yan@Sun.COM 		DEBUG0("Failed to map config space!\n");
260910923SEvan.Yan@Sun.COM 		entry->error = PCICFG_FAILURE;
261010923SEvan.Yan@Sun.COM 		return (DDI_WALK_TERMINATE);
261110923SEvan.Yan@Sun.COM 	}
261210923SEvan.Yan@Sun.COM 
261310923SEvan.Yan@Sun.COM 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
261410923SEvan.Yan@Sun.COM 
261510923SEvan.Yan@Sun.COM 	/*
261610923SEvan.Yan@Sun.COM 	 * If its a bridge - just record the highest bus seen
261710923SEvan.Yan@Sun.COM 	 */
261810923SEvan.Yan@Sun.COM 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
261910923SEvan.Yan@Sun.COM 
262010923SEvan.Yan@Sun.COM 		if (entry->highest_bus < pci_config_get8(handle,
262110923SEvan.Yan@Sun.COM 		    PCI_BCNF_SECBUS)) {
262210923SEvan.Yan@Sun.COM 			entry->highest_bus =
262310923SEvan.Yan@Sun.COM 			    pci_config_get8(handle, PCI_BCNF_SECBUS);
262410923SEvan.Yan@Sun.COM 		}
262510923SEvan.Yan@Sun.COM 
262610923SEvan.Yan@Sun.COM 		(void) pcicfg_config_teardown(&handle);
262710923SEvan.Yan@Sun.COM 		entry->error = PCICFG_FAILURE;
262810923SEvan.Yan@Sun.COM 		return (DDI_WALK_CONTINUE);
262910923SEvan.Yan@Sun.COM 	} else {
263010923SEvan.Yan@Sun.COM 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
263110923SEvan.Yan@Sun.COM 		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp,
263210923SEvan.Yan@Sun.COM 		    &length) != DDI_PROP_SUCCESS) {
263310923SEvan.Yan@Sun.COM 			/*
263410923SEvan.Yan@Sun.COM 			 * If one node in (the subtree of nodes)
263510923SEvan.Yan@Sun.COM 			 * does'nt have a "reg" property fail the
263610923SEvan.Yan@Sun.COM 			 * allocation.
263710923SEvan.Yan@Sun.COM 			 */
263810923SEvan.Yan@Sun.COM 			entry->memory_len = 0;
263910923SEvan.Yan@Sun.COM 			entry->io_len = 0;
264010923SEvan.Yan@Sun.COM 			entry->error = PCICFG_FAILURE;
264110923SEvan.Yan@Sun.COM 			return (DDI_WALK_TERMINATE);
264210923SEvan.Yan@Sun.COM 		}
264310923SEvan.Yan@Sun.COM 		/*
264410923SEvan.Yan@Sun.COM 		 * For each "reg" property with a length, add that to the
264510923SEvan.Yan@Sun.COM 		 * total memory (or I/O) to allocate.
264610923SEvan.Yan@Sun.COM 		 */
264710923SEvan.Yan@Sun.COM 		rcount = length / sizeof (pci_regspec_t);
264810923SEvan.Yan@Sun.COM 
264910923SEvan.Yan@Sun.COM 		for (i = 0; i < rcount; i++) {
265010923SEvan.Yan@Sun.COM 
265110923SEvan.Yan@Sun.COM 			switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
265210923SEvan.Yan@Sun.COM 
265310923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
265410923SEvan.Yan@Sun.COM 				mem_request->ra_len =
265510923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low +
265610923SEvan.Yan@Sun.COM 				    PCICFG_ROUND_UP(mem_request->ra_len,
265710923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low);
265810923SEvan.Yan@Sun.COM 				DEBUG1("ADDING 32 --->0x%x\n",
265910923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low);
266010923SEvan.Yan@Sun.COM 
266110923SEvan.Yan@Sun.COM 			break;
266210923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
266310923SEvan.Yan@Sun.COM 				mem_request->ra_len =
266410923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low +
266510923SEvan.Yan@Sun.COM 				    PCICFG_ROUND_UP(mem_request->ra_len,
266610923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low);
266710923SEvan.Yan@Sun.COM 				DEBUG1("ADDING 64 --->0x%x\n",
266810923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low);
266910923SEvan.Yan@Sun.COM 
267010923SEvan.Yan@Sun.COM 			break;
267110923SEvan.Yan@Sun.COM 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
267210923SEvan.Yan@Sun.COM 				io_request->ra_len =
267310923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low +
267410923SEvan.Yan@Sun.COM 				    PCICFG_ROUND_UP(io_request->ra_len,
267510923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low);
267610923SEvan.Yan@Sun.COM 				DEBUG1("ADDING I/O --->0x%x\n",
267710923SEvan.Yan@Sun.COM 				    pci_rp[i].pci_size_low);
267810923SEvan.Yan@Sun.COM 			break;
267910923SEvan.Yan@Sun.COM 			default:
268010923SEvan.Yan@Sun.COM 			    /* Config space register - not included */
268110923SEvan.Yan@Sun.COM 			break;
268210923SEvan.Yan@Sun.COM 			}
268310923SEvan.Yan@Sun.COM 		}
268410923SEvan.Yan@Sun.COM 
268510923SEvan.Yan@Sun.COM 		/*
268610923SEvan.Yan@Sun.COM 		 * free the memory allocated by ddi_getlongprop
268710923SEvan.Yan@Sun.COM 		 */
268810923SEvan.Yan@Sun.COM 		kmem_free(pci_rp, length);
268910923SEvan.Yan@Sun.COM 
269010923SEvan.Yan@Sun.COM 		/*
269110923SEvan.Yan@Sun.COM 		 * continue the walk to the next sibling to sum memory
269210923SEvan.Yan@Sun.COM 		 */
269310923SEvan.Yan@Sun.COM 
269410923SEvan.Yan@Sun.COM 		(void) pcicfg_config_teardown(&handle);
269510923SEvan.Yan@Sun.COM 
269610923SEvan.Yan@Sun.COM 		return (DDI_WALK_CONTINUE);
269710923SEvan.Yan@Sun.COM 	}
269810923SEvan.Yan@Sun.COM }
269910923SEvan.Yan@Sun.COM 
270010923SEvan.Yan@Sun.COM static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)270110923SEvan.Yan@Sun.COM pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
270210923SEvan.Yan@Sun.COM {
270310923SEvan.Yan@Sun.COM 	pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl;
270410923SEvan.Yan@Sun.COM 	pci_regspec_t *pci_ap;
270510923SEvan.Yan@Sun.COM 	pcicfg_range_t *ranges;
270610923SEvan.Yan@Sun.COM 	int length;
270710923SEvan.Yan@Sun.COM 	int rcount;
270810923SEvan.Yan@Sun.COM 	int i;
270910923SEvan.Yan@Sun.COM 
271010923SEvan.Yan@Sun.COM 	entry_p->error = PCICFG_SUCCESS;
271110923SEvan.Yan@Sun.COM 
271210923SEvan.Yan@Sun.COM 	if (dip == entry_p->dip) {
271310923SEvan.Yan@Sun.COM 		DEBUG0("Don't include parent bridge node\n");
271410923SEvan.Yan@Sun.COM 		return (DDI_WALK_CONTINUE);
271510923SEvan.Yan@Sun.COM 	}
271610923SEvan.Yan@Sun.COM 
271710923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
271810923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "ranges",
271910923SEvan.Yan@Sun.COM 	    (caddr_t)&ranges,  &length) != DDI_PROP_SUCCESS) {
272010923SEvan.Yan@Sun.COM 		DEBUG0("Node doesn't have ranges\n");
272110923SEvan.Yan@Sun.COM 		goto ap;
272210923SEvan.Yan@Sun.COM 	}
272310923SEvan.Yan@Sun.COM 
272410923SEvan.Yan@Sun.COM 	rcount = length / sizeof (pcicfg_range_t);
272510923SEvan.Yan@Sun.COM 
272610923SEvan.Yan@Sun.COM 	for (i = 0; i < rcount; i++) {
272710923SEvan.Yan@Sun.COM 		uint64_t base;
272810923SEvan.Yan@Sun.COM 		uint64_t mid = ranges[i].child_mid;
272910923SEvan.Yan@Sun.COM 		uint64_t lo = ranges[i].child_lo;
273010923SEvan.Yan@Sun.COM 		uint64_t size = ranges[i].size_lo;
273110923SEvan.Yan@Sun.COM 
273210923SEvan.Yan@Sun.COM 		switch (PCI_REG_ADDR_G(ranges[i].child_hi)) {
273310923SEvan.Yan@Sun.COM 
273410923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
273510923SEvan.Yan@Sun.COM 			base = entry_p->memory_base;
273610923SEvan.Yan@Sun.COM 			entry_p->memory_base = MAX(base, lo + size);
273710923SEvan.Yan@Sun.COM 			break;
273810923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
273910923SEvan.Yan@Sun.COM 			base = entry_p->memory_base;
274010923SEvan.Yan@Sun.COM 			entry_p->memory_base = MAX(base,
274110923SEvan.Yan@Sun.COM 			    PCICFG_LADDR(lo, mid) + size);
274210923SEvan.Yan@Sun.COM 			break;
274310923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
274410923SEvan.Yan@Sun.COM 			base = entry_p->io_base;
274510923SEvan.Yan@Sun.COM 			entry_p->io_base = MAX(base, lo + size);
274610923SEvan.Yan@Sun.COM 			break;
274710923SEvan.Yan@Sun.COM 		}
274810923SEvan.Yan@Sun.COM 	}
274910923SEvan.Yan@Sun.COM 
275010923SEvan.Yan@Sun.COM 	kmem_free(ranges, length);
275110923SEvan.Yan@Sun.COM 	return (DDI_WALK_CONTINUE);
275210923SEvan.Yan@Sun.COM 
275310923SEvan.Yan@Sun.COM ap:	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
275410923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses",
275510923SEvan.Yan@Sun.COM 	    (caddr_t)&pci_ap,  &length) != DDI_PROP_SUCCESS) {
275610923SEvan.Yan@Sun.COM 		DEBUG0("Node doesn't have assigned-addresses\n");
275710923SEvan.Yan@Sun.COM 		return (DDI_WALK_CONTINUE);
275810923SEvan.Yan@Sun.COM 	}
275910923SEvan.Yan@Sun.COM 
276010923SEvan.Yan@Sun.COM 	rcount = length / sizeof (pci_regspec_t);
276110923SEvan.Yan@Sun.COM 
276210923SEvan.Yan@Sun.COM 	for (i = 0; i < rcount; i++) {
276310923SEvan.Yan@Sun.COM 
276410923SEvan.Yan@Sun.COM 		switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
276510923SEvan.Yan@Sun.COM 
276610923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
276710923SEvan.Yan@Sun.COM 			if ((pci_ap[i].pci_phys_low +
276810923SEvan.Yan@Sun.COM 			    pci_ap[i].pci_size_low) >
276910923SEvan.Yan@Sun.COM 			    entry_p->memory_base) {
277010923SEvan.Yan@Sun.COM 				entry_p->memory_base =
277110923SEvan.Yan@Sun.COM 				    pci_ap[i].pci_phys_low +
277210923SEvan.Yan@Sun.COM 				    pci_ap[i].pci_size_low;
277310923SEvan.Yan@Sun.COM 			}
277410923SEvan.Yan@Sun.COM 		break;
277510923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
277610923SEvan.Yan@Sun.COM 			if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
277710923SEvan.Yan@Sun.COM 			    pci_ap[i].pci_phys_mid) +
277810923SEvan.Yan@Sun.COM 			    pci_ap[i].pci_size_low) >
277910923SEvan.Yan@Sun.COM 			    entry_p->memory_base) {
278010923SEvan.Yan@Sun.COM 				entry_p->memory_base = PCICFG_LADDR(
278110923SEvan.Yan@Sun.COM 				    pci_ap[i].pci_phys_low,
278210923SEvan.Yan@Sun.COM 				    pci_ap[i].pci_phys_mid) +
278310923SEvan.Yan@Sun.COM 				    pci_ap[i].pci_size_low;
278410923SEvan.Yan@Sun.COM 			}
278510923SEvan.Yan@Sun.COM 		break;
278610923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
278710923SEvan.Yan@Sun.COM 			if ((pci_ap[i].pci_phys_low +
278810923SEvan.Yan@Sun.COM 			    pci_ap[i].pci_size_low) >
278910923SEvan.Yan@Sun.COM 			    entry_p->io_base) {
279010923SEvan.Yan@Sun.COM 				entry_p->io_base =
279110923SEvan.Yan@Sun.COM 				    pci_ap[i].pci_phys_low +
279210923SEvan.Yan@Sun.COM 				    pci_ap[i].pci_size_low;
279310923SEvan.Yan@Sun.COM 			}
279410923SEvan.Yan@Sun.COM 		break;
279510923SEvan.Yan@Sun.COM 		}
279610923SEvan.Yan@Sun.COM 	}
279710923SEvan.Yan@Sun.COM 
279810923SEvan.Yan@Sun.COM 	/*
279910923SEvan.Yan@Sun.COM 	 * free the memory allocated by ddi_getlongprop
280010923SEvan.Yan@Sun.COM 	 */
280110923SEvan.Yan@Sun.COM 	kmem_free(pci_ap, length);
280210923SEvan.Yan@Sun.COM 
280310923SEvan.Yan@Sun.COM 	/*
280410923SEvan.Yan@Sun.COM 	 * continue the walk to the next sibling to sum memory
280510923SEvan.Yan@Sun.COM 	 */
280610923SEvan.Yan@Sun.COM 	return (DDI_WALK_CONTINUE);
280710923SEvan.Yan@Sun.COM }
280810923SEvan.Yan@Sun.COM 
280910923SEvan.Yan@Sun.COM static int
pcicfg_free_bridge_resources(dev_info_t * dip)281010923SEvan.Yan@Sun.COM pcicfg_free_bridge_resources(dev_info_t *dip)
281110923SEvan.Yan@Sun.COM {
281210923SEvan.Yan@Sun.COM 	pcicfg_range_t		*ranges;
281310923SEvan.Yan@Sun.COM 	uint_t			*bus;
281410923SEvan.Yan@Sun.COM 	int			k;
281510923SEvan.Yan@Sun.COM 	int			length;
281610923SEvan.Yan@Sun.COM 	int			i;
281710923SEvan.Yan@Sun.COM 
281810923SEvan.Yan@Sun.COM 
281910923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
282010923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
282110923SEvan.Yan@Sun.COM 	    &length) != DDI_PROP_SUCCESS) {
282210923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read ranges property\n");
282310923SEvan.Yan@Sun.COM 		if (ddi_get_child(dip)) {
282410923SEvan.Yan@Sun.COM 			cmn_err(CE_WARN, "No ranges property found for %s",
282510923SEvan.Yan@Sun.COM 			    ddi_get_name(dip));
282610923SEvan.Yan@Sun.COM 			/*
282710923SEvan.Yan@Sun.COM 			 * strictly speaking, we can check for children with
282810923SEvan.Yan@Sun.COM 			 * assigned-addresses but for now it is better to
282910923SEvan.Yan@Sun.COM 			 * be conservative and assume that if there are child
283010923SEvan.Yan@Sun.COM 			 * nodes, then they do consume PCI memory or IO
283110923SEvan.Yan@Sun.COM 			 * resources, Hence return failure.
283210923SEvan.Yan@Sun.COM 			 */
283310923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
283410923SEvan.Yan@Sun.COM 		}
283510923SEvan.Yan@Sun.COM 		length = 0;
283610923SEvan.Yan@Sun.COM 
283710923SEvan.Yan@Sun.COM 	}
283810923SEvan.Yan@Sun.COM 
283910923SEvan.Yan@Sun.COM 	for (i = 0; i < length / sizeof (pcicfg_range_t); i++) {
284010923SEvan.Yan@Sun.COM 		if (ranges[i].size_lo != 0 ||
284110923SEvan.Yan@Sun.COM 		    ranges[i].size_hi != 0) {
284210923SEvan.Yan@Sun.COM 			switch (ranges[i].parent_hi & PCI_REG_ADDR_M) {
284310923SEvan.Yan@Sun.COM 				case PCI_ADDR_IO:
284410923SEvan.Yan@Sun.COM 					DEBUG2("Free I/O    "
284510923SEvan.Yan@Sun.COM 					    "base/length = [0x%x]/[0x%x]\n",
284610923SEvan.Yan@Sun.COM 					    ranges[i].child_lo,
284710923SEvan.Yan@Sun.COM 					    ranges[i].size_lo);
284810923SEvan.Yan@Sun.COM 					if (ndi_ra_free(ddi_get_parent(dip),
284910923SEvan.Yan@Sun.COM 					    (uint64_t)ranges[i].child_lo,
285010923SEvan.Yan@Sun.COM 					    (uint64_t)ranges[i].size_lo,
285110923SEvan.Yan@Sun.COM 					    NDI_RA_TYPE_IO, NDI_RA_PASS)
285210923SEvan.Yan@Sun.COM 					    != NDI_SUCCESS) {
285310923SEvan.Yan@Sun.COM 						DEBUG0("Trouble freeing "
285410923SEvan.Yan@Sun.COM 						    "PCI i/o space\n");
285510923SEvan.Yan@Sun.COM 						kmem_free(ranges, length);
285610923SEvan.Yan@Sun.COM 						return (PCICFG_FAILURE);
285710923SEvan.Yan@Sun.COM 					}
285810923SEvan.Yan@Sun.COM 				break;
285910923SEvan.Yan@Sun.COM 				case PCI_ADDR_MEM32:
286010923SEvan.Yan@Sun.COM 				case PCI_ADDR_MEM64:
286110923SEvan.Yan@Sun.COM 					DEBUG3("Free Memory base/length = "
286210923SEvan.Yan@Sun.COM 					    "[0x%x.%x]/[0x%x]\n",
286310923SEvan.Yan@Sun.COM 					    ranges[i].child_mid,
286410923SEvan.Yan@Sun.COM 					    ranges[i].child_lo,
286510923SEvan.Yan@Sun.COM 					    ranges[i].size_lo)
286610923SEvan.Yan@Sun.COM 					if (ndi_ra_free(ddi_get_parent(dip),
286710923SEvan.Yan@Sun.COM 					    PCICFG_LADDR(ranges[i].child_lo,
286810923SEvan.Yan@Sun.COM 					    ranges[i].child_mid),
286910923SEvan.Yan@Sun.COM 					    (uint64_t)ranges[i].size_lo,
287010923SEvan.Yan@Sun.COM 					    NDI_RA_TYPE_MEM, NDI_RA_PASS)
287110923SEvan.Yan@Sun.COM 					    != NDI_SUCCESS) {
287210923SEvan.Yan@Sun.COM 						DEBUG0("Trouble freeing "
287310923SEvan.Yan@Sun.COM 						    "PCI memory space\n");
287410923SEvan.Yan@Sun.COM 						kmem_free(ranges, length);
287510923SEvan.Yan@Sun.COM 						return (PCICFG_FAILURE);
287610923SEvan.Yan@Sun.COM 					}
287710923SEvan.Yan@Sun.COM 				break;
287810923SEvan.Yan@Sun.COM 				default:
287910923SEvan.Yan@Sun.COM 					DEBUG0("Unknown memory space\n");
288010923SEvan.Yan@Sun.COM 				break;
288110923SEvan.Yan@Sun.COM 			}
288210923SEvan.Yan@Sun.COM 		}
288310923SEvan.Yan@Sun.COM 	}
288410923SEvan.Yan@Sun.COM 
288510923SEvan.Yan@Sun.COM 	if (length)
288610923SEvan.Yan@Sun.COM 		kmem_free(ranges, length);
288710923SEvan.Yan@Sun.COM 
288810923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
288910923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
289010923SEvan.Yan@Sun.COM 	    &k) != DDI_PROP_SUCCESS) {
289110923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read bus-range property\n");
289210923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
289310923SEvan.Yan@Sun.COM 	}
289410923SEvan.Yan@Sun.COM 
289510923SEvan.Yan@Sun.COM 	DEBUG2("Need to free bus [%d] range [%d]\n",
289610923SEvan.Yan@Sun.COM 	    bus[0], bus[1] - bus[0] + 1);
289710923SEvan.Yan@Sun.COM 
289810923SEvan.Yan@Sun.COM 	if (ndi_ra_free(ddi_get_parent(dip),
289910923SEvan.Yan@Sun.COM 	    (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
290010923SEvan.Yan@Sun.COM 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
290110923SEvan.Yan@Sun.COM 		/*EMPTY*/
290210923SEvan.Yan@Sun.COM 		DEBUG0("Failed to free a bus number\n");
290310923SEvan.Yan@Sun.COM 	}
290410923SEvan.Yan@Sun.COM 	/*
290510923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
290610923SEvan.Yan@Sun.COM 	 */
290710923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)bus, k);
290810923SEvan.Yan@Sun.COM 
290910923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
291010923SEvan.Yan@Sun.COM }
291110923SEvan.Yan@Sun.COM 
291210923SEvan.Yan@Sun.COM static int
pcicfg_free_device_resources(dev_info_t * dip,pcicfg_flags_t flags)291310923SEvan.Yan@Sun.COM pcicfg_free_device_resources(dev_info_t *dip, pcicfg_flags_t flags)
291410923SEvan.Yan@Sun.COM {
291510923SEvan.Yan@Sun.COM 	pci_regspec_t *assigned;
291610923SEvan.Yan@Sun.COM 
291710923SEvan.Yan@Sun.COM 	int length;
291810923SEvan.Yan@Sun.COM 	int acount;
291910923SEvan.Yan@Sun.COM 	int i;
292010923SEvan.Yan@Sun.COM 
292110923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
292210923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
292310923SEvan.Yan@Sun.COM 	    &length) != DDI_PROP_SUCCESS) {
292410923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read assigned-addresses property\n");
292510923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
292610923SEvan.Yan@Sun.COM 	}
292710923SEvan.Yan@Sun.COM 
292810923SEvan.Yan@Sun.COM 	/*
292910923SEvan.Yan@Sun.COM 	 * For each "assigned-addresses" property entry with a length,
293010923SEvan.Yan@Sun.COM 	 * call the memory allocation routines to return the
293110923SEvan.Yan@Sun.COM 	 * resource.
293210923SEvan.Yan@Sun.COM 	 */
293310923SEvan.Yan@Sun.COM 	acount = length / sizeof (pci_regspec_t);
293410923SEvan.Yan@Sun.COM 	for (i = 0; i < acount; i++) {
293510923SEvan.Yan@Sun.COM 		/*
293610923SEvan.Yan@Sun.COM 		 * Workaround for Devconf (x86) bug to skip extra entries
293710923SEvan.Yan@Sun.COM 		 * beyond the PCI_CONF_BASE5 offset. But we want to free up
293810923SEvan.Yan@Sun.COM 		 * any memory for expansion roms if allocated.
293910923SEvan.Yan@Sun.COM 		 */
294010923SEvan.Yan@Sun.COM 		if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) &&
294110923SEvan.Yan@Sun.COM 		    (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM))
294210923SEvan.Yan@Sun.COM 			break;
294310923SEvan.Yan@Sun.COM 
294410923SEvan.Yan@Sun.COM 		if (pcicfg_free_resource(dip, assigned[i], flags)) {
294510923SEvan.Yan@Sun.COM 			DEBUG1("pcicfg_free_device_resources - Trouble freeing "
294610923SEvan.Yan@Sun.COM 			    "%x\n", assigned[i].pci_phys_hi);
294710923SEvan.Yan@Sun.COM 			/*
294810923SEvan.Yan@Sun.COM 			 * Don't forget to free up memory from ddi_getlongprop
294910923SEvan.Yan@Sun.COM 			 */
295010923SEvan.Yan@Sun.COM 			kmem_free((caddr_t)assigned, length);
295110923SEvan.Yan@Sun.COM 
295210923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
295310923SEvan.Yan@Sun.COM 		}
295410923SEvan.Yan@Sun.COM 	}
295510923SEvan.Yan@Sun.COM 	kmem_free(assigned, length);
295610923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
295710923SEvan.Yan@Sun.COM }
295810923SEvan.Yan@Sun.COM 
295910923SEvan.Yan@Sun.COM static int
pcicfg_free_resources(dev_info_t * dip,pcicfg_flags_t flags)296010923SEvan.Yan@Sun.COM pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
296110923SEvan.Yan@Sun.COM {
296210923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
296310923SEvan.Yan@Sun.COM 	uint8_t header_type;
296410923SEvan.Yan@Sun.COM 
296510923SEvan.Yan@Sun.COM 	if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
296610923SEvan.Yan@Sun.COM 		DEBUG0("Failed to map config space!\n");
296710923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
296810923SEvan.Yan@Sun.COM 	}
296910923SEvan.Yan@Sun.COM 
297010923SEvan.Yan@Sun.COM 	header_type = pci_config_get8(handle, PCI_CONF_HEADER);
297110923SEvan.Yan@Sun.COM 
297210923SEvan.Yan@Sun.COM 	(void) pci_config_teardown(&handle);
297310923SEvan.Yan@Sun.COM 
297410923SEvan.Yan@Sun.COM 	/*
297510923SEvan.Yan@Sun.COM 	 * A different algorithm is used for bridges and leaf devices.
297610923SEvan.Yan@Sun.COM 	 */
297710923SEvan.Yan@Sun.COM 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
297810923SEvan.Yan@Sun.COM 		/*
297910923SEvan.Yan@Sun.COM 		 * We only support readonly probing for leaf devices.
298010923SEvan.Yan@Sun.COM 		 */
298110923SEvan.Yan@Sun.COM 		if (flags & PCICFG_FLAG_READ_ONLY)
298210923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
298310923SEvan.Yan@Sun.COM 
298410923SEvan.Yan@Sun.COM 		if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
298510923SEvan.Yan@Sun.COM 			DEBUG0("Failed freeing up bridge resources\n");
298610923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
298710923SEvan.Yan@Sun.COM 		}
298810923SEvan.Yan@Sun.COM 	} else {
298910923SEvan.Yan@Sun.COM 		if (pcicfg_free_device_resources(dip, flags)
299010923SEvan.Yan@Sun.COM 		    != PCICFG_SUCCESS) {
299110923SEvan.Yan@Sun.COM 			DEBUG0("Failed freeing up device resources\n");
299210923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
299310923SEvan.Yan@Sun.COM 		}
299410923SEvan.Yan@Sun.COM 	}
299510923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
299610923SEvan.Yan@Sun.COM }
299710923SEvan.Yan@Sun.COM 
299810923SEvan.Yan@Sun.COM #ifndef _DONT_USE_1275_GENERIC_NAMES
299910923SEvan.Yan@Sun.COM static char *
pcicfg_get_class_name(uint32_t classcode)300010923SEvan.Yan@Sun.COM pcicfg_get_class_name(uint32_t classcode)
300110923SEvan.Yan@Sun.COM {
300210923SEvan.Yan@Sun.COM 	struct pcicfg_name_entry *ptr;
300310923SEvan.Yan@Sun.COM 
300410923SEvan.Yan@Sun.COM 	for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
300510923SEvan.Yan@Sun.COM 		if (ptr->class_code == classcode) {
300610923SEvan.Yan@Sun.COM 			return (ptr->name);
300710923SEvan.Yan@Sun.COM 		}
300810923SEvan.Yan@Sun.COM 	}
300910923SEvan.Yan@Sun.COM 	return (NULL);
301010923SEvan.Yan@Sun.COM }
301110923SEvan.Yan@Sun.COM #endif /* _DONT_USE_1275_GENERIC_NAMES */
301210923SEvan.Yan@Sun.COM 
301310923SEvan.Yan@Sun.COM static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)301410923SEvan.Yan@Sun.COM pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
301510923SEvan.Yan@Sun.COM {
301610923SEvan.Yan@Sun.COM 	struct pcicfg_find_ctrl ctrl;
301710923SEvan.Yan@Sun.COM 	int count;
301810923SEvan.Yan@Sun.COM 
301910923SEvan.Yan@Sun.COM 	ctrl.device = device;
302010923SEvan.Yan@Sun.COM 	ctrl.function = function;
302110923SEvan.Yan@Sun.COM 	ctrl.dip = NULL;
302210923SEvan.Yan@Sun.COM 
302310923SEvan.Yan@Sun.COM 	ndi_devi_enter(dip, &count);
302410923SEvan.Yan@Sun.COM 	ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
302510923SEvan.Yan@Sun.COM 	ndi_devi_exit(dip, count);
302610923SEvan.Yan@Sun.COM 
302710923SEvan.Yan@Sun.COM 	return (ctrl.dip);
302810923SEvan.Yan@Sun.COM }
302910923SEvan.Yan@Sun.COM 
303010923SEvan.Yan@Sun.COM static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)303110923SEvan.Yan@Sun.COM pcicfg_match_dev(dev_info_t *dip, void *hdl)
303210923SEvan.Yan@Sun.COM {
303310923SEvan.Yan@Sun.COM 	struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
303410923SEvan.Yan@Sun.COM 	pci_regspec_t *pci_rp;
303510923SEvan.Yan@Sun.COM 	int length;
303610923SEvan.Yan@Sun.COM 	int pci_dev;
303710923SEvan.Yan@Sun.COM 	int pci_func;
303810923SEvan.Yan@Sun.COM 
303910923SEvan.Yan@Sun.COM 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
304010923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
304110923SEvan.Yan@Sun.COM 	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
304210923SEvan.Yan@Sun.COM 		ctrl->dip = NULL;
304310923SEvan.Yan@Sun.COM 		return (DDI_WALK_TERMINATE);
304410923SEvan.Yan@Sun.COM 	}
304510923SEvan.Yan@Sun.COM 
304610923SEvan.Yan@Sun.COM 	/* get the PCI device address info */
304710923SEvan.Yan@Sun.COM 	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
304810923SEvan.Yan@Sun.COM 	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
304910923SEvan.Yan@Sun.COM 
305010923SEvan.Yan@Sun.COM 	/*
305110923SEvan.Yan@Sun.COM 	 * free the memory allocated by ddi_prop_lookup_int_array
305210923SEvan.Yan@Sun.COM 	 */
305310923SEvan.Yan@Sun.COM 	ddi_prop_free(pci_rp);
305410923SEvan.Yan@Sun.COM 
305510923SEvan.Yan@Sun.COM 
305610923SEvan.Yan@Sun.COM 	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
305710923SEvan.Yan@Sun.COM 		/* found the match for the specified device address */
305810923SEvan.Yan@Sun.COM 		ctrl->dip = dip;
305910923SEvan.Yan@Sun.COM 		return (DDI_WALK_TERMINATE);
306010923SEvan.Yan@Sun.COM 	}
306110923SEvan.Yan@Sun.COM 
306210923SEvan.Yan@Sun.COM 	/*
306310923SEvan.Yan@Sun.COM 	 * continue the walk to the next sibling to look for a match.
306410923SEvan.Yan@Sun.COM 	 */
306510923SEvan.Yan@Sun.COM 	return (DDI_WALK_PRUNECHILD);
306610923SEvan.Yan@Sun.COM }
306710923SEvan.Yan@Sun.COM 
306810923SEvan.Yan@Sun.COM static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)306910923SEvan.Yan@Sun.COM pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
307010923SEvan.Yan@Sun.COM {
307110923SEvan.Yan@Sun.COM 	int		alen;
307210923SEvan.Yan@Sun.COM 	pci_regspec_t	*assigned;
307310923SEvan.Yan@Sun.COM 	caddr_t		newreg;
307410923SEvan.Yan@Sun.COM 	uint_t		status;
307510923SEvan.Yan@Sun.COM 
307610923SEvan.Yan@Sun.COM 	DEBUG0("pcicfg_update_assigned_prop()\n");
307710923SEvan.Yan@Sun.COM 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
307810923SEvan.Yan@Sun.COM 	    "assigned-addresses", (caddr_t)&assigned, &alen);
307910923SEvan.Yan@Sun.COM 	switch (status) {
308010923SEvan.Yan@Sun.COM 		case DDI_PROP_SUCCESS:
308110923SEvan.Yan@Sun.COM 		break;
308210923SEvan.Yan@Sun.COM 		case DDI_PROP_NO_MEMORY:
308310923SEvan.Yan@Sun.COM 			DEBUG0("no memory for assigned-addresses property\n");
308410923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
308510923SEvan.Yan@Sun.COM 		default:
308610923SEvan.Yan@Sun.COM 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
308710923SEvan.Yan@Sun.COM 			    "assigned-addresses", (int *)newone,
308810923SEvan.Yan@Sun.COM 			    sizeof (*newone)/sizeof (int));
308910923SEvan.Yan@Sun.COM 
309010923SEvan.Yan@Sun.COM 			(void) pcicfg_dump_assigned(dip);
309110923SEvan.Yan@Sun.COM 
309210923SEvan.Yan@Sun.COM 			return (PCICFG_SUCCESS);
309310923SEvan.Yan@Sun.COM 	}
309410923SEvan.Yan@Sun.COM 
309510923SEvan.Yan@Sun.COM 	/*
309610923SEvan.Yan@Sun.COM 	 * Allocate memory for the existing
309710923SEvan.Yan@Sun.COM 	 * assigned-addresses(s) plus one and then
309810923SEvan.Yan@Sun.COM 	 * build it.
309910923SEvan.Yan@Sun.COM 	 */
310010923SEvan.Yan@Sun.COM 
310110923SEvan.Yan@Sun.COM 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
310210923SEvan.Yan@Sun.COM 
310310923SEvan.Yan@Sun.COM 	bcopy(assigned, newreg, alen);
310410923SEvan.Yan@Sun.COM 	bcopy(newone, newreg + alen, sizeof (*newone));
310510923SEvan.Yan@Sun.COM 
310610923SEvan.Yan@Sun.COM 	/*
310710923SEvan.Yan@Sun.COM 	 * Write out the new "assigned-addresses" spec
310810923SEvan.Yan@Sun.COM 	 */
310910923SEvan.Yan@Sun.COM 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
311010923SEvan.Yan@Sun.COM 	    "assigned-addresses", (int *)newreg,
311110923SEvan.Yan@Sun.COM 	    (alen + sizeof (*newone))/sizeof (int));
311210923SEvan.Yan@Sun.COM 
311310923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
311410923SEvan.Yan@Sun.COM 
311510923SEvan.Yan@Sun.COM 	/*
311610923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
311710923SEvan.Yan@Sun.COM 	 */
311810923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)assigned, alen);
311910923SEvan.Yan@Sun.COM 
312010923SEvan.Yan@Sun.COM 	(void) pcicfg_dump_assigned(dip);
312110923SEvan.Yan@Sun.COM 
312210923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
312310923SEvan.Yan@Sun.COM }
312410923SEvan.Yan@Sun.COM static int
pcicfg_update_ranges_prop(dev_info_t * dip,pcicfg_range_t * addition)312510923SEvan.Yan@Sun.COM pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition)
312610923SEvan.Yan@Sun.COM {
312710923SEvan.Yan@Sun.COM 	int		rlen;
312810923SEvan.Yan@Sun.COM 	pcicfg_range_t	*ranges;
312910923SEvan.Yan@Sun.COM 	caddr_t		newreg;
313010923SEvan.Yan@Sun.COM 	uint_t		status;
313110923SEvan.Yan@Sun.COM 
313210923SEvan.Yan@Sun.COM 	status = ddi_getlongprop(DDI_DEV_T_ANY,
313310923SEvan.Yan@Sun.COM 	    dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen);
313410923SEvan.Yan@Sun.COM 
313510923SEvan.Yan@Sun.COM 
313610923SEvan.Yan@Sun.COM 	switch (status) {
313710923SEvan.Yan@Sun.COM 		case DDI_PROP_SUCCESS:
313810923SEvan.Yan@Sun.COM 		break;
313910923SEvan.Yan@Sun.COM 		case DDI_PROP_NO_MEMORY:
314010923SEvan.Yan@Sun.COM 			DEBUG0("ranges present, but unable to get memory\n");
314110923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
314210923SEvan.Yan@Sun.COM 		default:
314310923SEvan.Yan@Sun.COM 			DEBUG0("no ranges property - creating one\n");
314410923SEvan.Yan@Sun.COM 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
314510923SEvan.Yan@Sun.COM 			    dip, "ranges", (int *)addition,
314610923SEvan.Yan@Sun.COM 			    sizeof (pcicfg_range_t)/sizeof (int))
314710923SEvan.Yan@Sun.COM 			    != DDI_SUCCESS) {
314810923SEvan.Yan@Sun.COM 				DEBUG0("Did'nt create ranges property\n");
314910923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
315010923SEvan.Yan@Sun.COM 			}
315110923SEvan.Yan@Sun.COM 			return (PCICFG_SUCCESS);
315210923SEvan.Yan@Sun.COM 	}
315310923SEvan.Yan@Sun.COM 
315410923SEvan.Yan@Sun.COM 	/*
315510923SEvan.Yan@Sun.COM 	 * Allocate memory for the existing reg(s) plus one and then
315610923SEvan.Yan@Sun.COM 	 * build it.
315710923SEvan.Yan@Sun.COM 	 */
315810923SEvan.Yan@Sun.COM 	newreg = kmem_zalloc(rlen + sizeof (pcicfg_range_t), KM_SLEEP);
315910923SEvan.Yan@Sun.COM 
316010923SEvan.Yan@Sun.COM 	bcopy(ranges, newreg, rlen);
316110923SEvan.Yan@Sun.COM 	bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t));
316210923SEvan.Yan@Sun.COM 
316310923SEvan.Yan@Sun.COM 	/*
316410923SEvan.Yan@Sun.COM 	 * Write out the new "ranges" property
316510923SEvan.Yan@Sun.COM 	 */
316610923SEvan.Yan@Sun.COM 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
316710923SEvan.Yan@Sun.COM 	    dip, "ranges", (int *)newreg,
316810923SEvan.Yan@Sun.COM 	    (rlen + sizeof (pcicfg_range_t))/sizeof (int));
316910923SEvan.Yan@Sun.COM 
317010923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t));
317110923SEvan.Yan@Sun.COM 
317210923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)ranges, rlen);
317310923SEvan.Yan@Sun.COM 
317410923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
317510923SEvan.Yan@Sun.COM }
317610923SEvan.Yan@Sun.COM 
317710923SEvan.Yan@Sun.COM static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)317810923SEvan.Yan@Sun.COM pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
317910923SEvan.Yan@Sun.COM {
318010923SEvan.Yan@Sun.COM 	int		rlen;
318110923SEvan.Yan@Sun.COM 	pci_regspec_t	*reg;
318210923SEvan.Yan@Sun.COM 	caddr_t		newreg;
318310923SEvan.Yan@Sun.COM 	uint32_t	hiword;
318410923SEvan.Yan@Sun.COM 	pci_regspec_t	addition;
318510923SEvan.Yan@Sun.COM 	uint32_t	size;
318610923SEvan.Yan@Sun.COM 	uint_t		status;
318710923SEvan.Yan@Sun.COM 
318810923SEvan.Yan@Sun.COM 	status = ddi_getlongprop(DDI_DEV_T_ANY,
318910923SEvan.Yan@Sun.COM 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
319010923SEvan.Yan@Sun.COM 
319110923SEvan.Yan@Sun.COM 	switch (status) {
319210923SEvan.Yan@Sun.COM 		case DDI_PROP_SUCCESS:
319310923SEvan.Yan@Sun.COM 		break;
319410923SEvan.Yan@Sun.COM 		case DDI_PROP_NO_MEMORY:
319510923SEvan.Yan@Sun.COM 			DEBUG0("reg present, but unable to get memory\n");
319610923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
319710923SEvan.Yan@Sun.COM 		default:
319810923SEvan.Yan@Sun.COM 			DEBUG0("no reg property\n");
319910923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
320010923SEvan.Yan@Sun.COM 	}
320110923SEvan.Yan@Sun.COM 
320210923SEvan.Yan@Sun.COM 	/*
320310923SEvan.Yan@Sun.COM 	 * Allocate memory for the existing reg(s) plus one and then
320410923SEvan.Yan@Sun.COM 	 * build it.
320510923SEvan.Yan@Sun.COM 	 */
320610923SEvan.Yan@Sun.COM 	newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
320710923SEvan.Yan@Sun.COM 
320810923SEvan.Yan@Sun.COM 	/*
320910923SEvan.Yan@Sun.COM 	 * Build the regspec, then add it to the existing one(s)
321010923SEvan.Yan@Sun.COM 	 */
321110923SEvan.Yan@Sun.COM 
321210923SEvan.Yan@Sun.COM 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
321310923SEvan.Yan@Sun.COM 	    PCI_REG_DEV_G(reg->pci_phys_hi),
321410923SEvan.Yan@Sun.COM 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
321510923SEvan.Yan@Sun.COM 
321610923SEvan.Yan@Sun.COM 	if (reg_offset == PCI_CONF_ROM) {
321710923SEvan.Yan@Sun.COM 		size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
321810923SEvan.Yan@Sun.COM 		hiword |= PCI_ADDR_MEM32;
321910923SEvan.Yan@Sun.COM 	} else {
322010923SEvan.Yan@Sun.COM 		size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
322110923SEvan.Yan@Sun.COM 
322210923SEvan.Yan@Sun.COM 		if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
322310923SEvan.Yan@Sun.COM 			if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
322410923SEvan.Yan@Sun.COM 				hiword |= PCI_ADDR_MEM32;
322510923SEvan.Yan@Sun.COM 			} else if ((PCI_BASE_TYPE_M & regvalue)
322610923SEvan.Yan@Sun.COM 			    == PCI_BASE_TYPE_ALL) {
322710923SEvan.Yan@Sun.COM 				hiword |= PCI_ADDR_MEM64;
322810923SEvan.Yan@Sun.COM 			}
322910923SEvan.Yan@Sun.COM 		} else {
323010923SEvan.Yan@Sun.COM 			hiword |= PCI_ADDR_IO;
323110923SEvan.Yan@Sun.COM 		}
323210923SEvan.Yan@Sun.COM 	}
323310923SEvan.Yan@Sun.COM 
323410923SEvan.Yan@Sun.COM 	addition.pci_phys_hi = hiword;
323510923SEvan.Yan@Sun.COM 	addition.pci_phys_mid = 0;
323610923SEvan.Yan@Sun.COM 	addition.pci_phys_low = 0;
323710923SEvan.Yan@Sun.COM 	addition.pci_size_hi = 0;
323810923SEvan.Yan@Sun.COM 	addition.pci_size_low = size;
323910923SEvan.Yan@Sun.COM 
324010923SEvan.Yan@Sun.COM 	bcopy(reg, newreg, rlen);
324110923SEvan.Yan@Sun.COM 	bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
324210923SEvan.Yan@Sun.COM 
324310923SEvan.Yan@Sun.COM 	/*
324410923SEvan.Yan@Sun.COM 	 * Write out the new "reg" property
324510923SEvan.Yan@Sun.COM 	 */
324610923SEvan.Yan@Sun.COM 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
324710923SEvan.Yan@Sun.COM 	    dip, "reg", (int *)newreg,
324810923SEvan.Yan@Sun.COM 	    (rlen + sizeof (pci_regspec_t))/sizeof (int));
324910923SEvan.Yan@Sun.COM 
325010923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
325110923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)reg, rlen);
325210923SEvan.Yan@Sun.COM 
325310923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
325410923SEvan.Yan@Sun.COM }
325510923SEvan.Yan@Sun.COM static int
pcicfg_update_available_prop(dev_info_t * dip,pci_regspec_t * newone)325610923SEvan.Yan@Sun.COM pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone)
325710923SEvan.Yan@Sun.COM {
325810923SEvan.Yan@Sun.COM 	int		alen;
325910923SEvan.Yan@Sun.COM 	pci_regspec_t	*avail_p;
326010923SEvan.Yan@Sun.COM 	caddr_t		new_avail;
326110923SEvan.Yan@Sun.COM 	uint_t		status;
326210923SEvan.Yan@Sun.COM 
326310923SEvan.Yan@Sun.COM 	DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n",
326410923SEvan.Yan@Sun.COM 	    newone->pci_phys_low, newone->pci_size_low);
326510923SEvan.Yan@Sun.COM 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
326610923SEvan.Yan@Sun.COM 	    "available", (caddr_t)&avail_p, &alen);
326710923SEvan.Yan@Sun.COM 	switch (status) {
326810923SEvan.Yan@Sun.COM 		case DDI_PROP_SUCCESS:
326910923SEvan.Yan@Sun.COM 			break;
327010923SEvan.Yan@Sun.COM 		case DDI_PROP_NO_MEMORY:
327110923SEvan.Yan@Sun.COM 			DEBUG0("no memory for available property\n");
327210923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
327310923SEvan.Yan@Sun.COM 		default:
327410923SEvan.Yan@Sun.COM 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
327510923SEvan.Yan@Sun.COM 			    "available", (int *)newone,
327610923SEvan.Yan@Sun.COM 			    sizeof (*newone)/sizeof (int));
327710923SEvan.Yan@Sun.COM 
327810923SEvan.Yan@Sun.COM 			return (PCICFG_SUCCESS);
327910923SEvan.Yan@Sun.COM 	}
328010923SEvan.Yan@Sun.COM 
328110923SEvan.Yan@Sun.COM 	/*
328210923SEvan.Yan@Sun.COM 	 * Allocate memory for the existing available plus one and then
328310923SEvan.Yan@Sun.COM 	 * build it.
328410923SEvan.Yan@Sun.COM 	 */
328510923SEvan.Yan@Sun.COM 	new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
328610923SEvan.Yan@Sun.COM 
328710923SEvan.Yan@Sun.COM 	bcopy(avail_p, new_avail, alen);
328810923SEvan.Yan@Sun.COM 	bcopy(newone, new_avail + alen, sizeof (*newone));
328910923SEvan.Yan@Sun.COM 
329010923SEvan.Yan@Sun.COM 	/* Write out the new "available" spec */
329110923SEvan.Yan@Sun.COM 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
329210923SEvan.Yan@Sun.COM 	    "available", (int *)new_avail,
329310923SEvan.Yan@Sun.COM 	    (alen + sizeof (*newone))/sizeof (int));
329410923SEvan.Yan@Sun.COM 
329510923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)new_avail, alen+sizeof (*newone));
329610923SEvan.Yan@Sun.COM 
329710923SEvan.Yan@Sun.COM 	/* Don't forget to free up memory from ddi_getlongprop */
329810923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)avail_p, alen);
329910923SEvan.Yan@Sun.COM 
330010923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
330110923SEvan.Yan@Sun.COM }
330210923SEvan.Yan@Sun.COM 
330310923SEvan.Yan@Sun.COM 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)330410923SEvan.Yan@Sun.COM pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
330510923SEvan.Yan@Sun.COM     uint32_t base, uint32_t base_hi, uint_t reg_offset)
330610923SEvan.Yan@Sun.COM {
330710923SEvan.Yan@Sun.COM 	int		rlen;
330810923SEvan.Yan@Sun.COM 	pci_regspec_t	*reg;
330910923SEvan.Yan@Sun.COM 	uint32_t	hiword;
331010923SEvan.Yan@Sun.COM 	pci_regspec_t	addition;
331110923SEvan.Yan@Sun.COM 	uint_t		status;
331210923SEvan.Yan@Sun.COM 
331310923SEvan.Yan@Sun.COM 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
331410923SEvan.Yan@Sun.COM 	    "reg", (caddr_t)&reg, &rlen);
331510923SEvan.Yan@Sun.COM 
331610923SEvan.Yan@Sun.COM 	switch (status) {
331710923SEvan.Yan@Sun.COM 		case DDI_PROP_SUCCESS:
331810923SEvan.Yan@Sun.COM 		break;
331910923SEvan.Yan@Sun.COM 		case DDI_PROP_NO_MEMORY:
332010923SEvan.Yan@Sun.COM 			DEBUG0("reg present, but unable to get memory\n");
332110923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
332210923SEvan.Yan@Sun.COM 		default:
332310923SEvan.Yan@Sun.COM 			/*
332410923SEvan.Yan@Sun.COM 			 * Since the config space "reg" entry should have been
332510923SEvan.Yan@Sun.COM 			 * created, we expect a "reg" property already
332610923SEvan.Yan@Sun.COM 			 * present here.
332710923SEvan.Yan@Sun.COM 			 */
332810923SEvan.Yan@Sun.COM 			DEBUG0("no reg property\n");
332910923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
333010923SEvan.Yan@Sun.COM 	}
333110923SEvan.Yan@Sun.COM 
333210923SEvan.Yan@Sun.COM 	/*
333310923SEvan.Yan@Sun.COM 	 * Build the regspec, then add it to the existing one(s)
333410923SEvan.Yan@Sun.COM 	 */
333510923SEvan.Yan@Sun.COM 
333610923SEvan.Yan@Sun.COM 	hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
333710923SEvan.Yan@Sun.COM 	    PCI_REG_DEV_G(reg->pci_phys_hi),
333810923SEvan.Yan@Sun.COM 	    PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
333910923SEvan.Yan@Sun.COM 
334010923SEvan.Yan@Sun.COM 	hiword |= PCI_REG_REL_M;
334110923SEvan.Yan@Sun.COM 
334210923SEvan.Yan@Sun.COM 	if (reg_offset == PCI_CONF_ROM) {
334310923SEvan.Yan@Sun.COM 		hiword |= PCI_ADDR_MEM32;
334410923SEvan.Yan@Sun.COM 
334510923SEvan.Yan@Sun.COM 		base = PCI_BASE_ROM_ADDR_M & base;
334610923SEvan.Yan@Sun.COM 	} else {
334710923SEvan.Yan@Sun.COM 		if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
334810923SEvan.Yan@Sun.COM 			if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
334910923SEvan.Yan@Sun.COM 				hiword |= PCI_ADDR_MEM32;
335010923SEvan.Yan@Sun.COM 			} else if ((PCI_BASE_TYPE_M & base)
335110923SEvan.Yan@Sun.COM 			    == PCI_BASE_TYPE_ALL) {
335210923SEvan.Yan@Sun.COM 				hiword |= PCI_ADDR_MEM64;
335310923SEvan.Yan@Sun.COM 			}
335410923SEvan.Yan@Sun.COM 
335510923SEvan.Yan@Sun.COM 			if (base & PCI_BASE_PREF_M)
335610923SEvan.Yan@Sun.COM 				hiword |= PCI_REG_PF_M;
335710923SEvan.Yan@Sun.COM 
335810923SEvan.Yan@Sun.COM 			base = PCI_BASE_M_ADDR_M & base;
335910923SEvan.Yan@Sun.COM 		} else {
336010923SEvan.Yan@Sun.COM 			hiword |= PCI_ADDR_IO;
336110923SEvan.Yan@Sun.COM 
336210923SEvan.Yan@Sun.COM 			base = PCI_BASE_IO_ADDR_M & base;
336310923SEvan.Yan@Sun.COM 			base_hi = 0;
336410923SEvan.Yan@Sun.COM 		}
336510923SEvan.Yan@Sun.COM 	}
336610923SEvan.Yan@Sun.COM 
336710923SEvan.Yan@Sun.COM 	addition.pci_phys_hi = hiword;
336810923SEvan.Yan@Sun.COM 	addition.pci_phys_mid = base_hi;
336910923SEvan.Yan@Sun.COM 	addition.pci_phys_low = base;
337010923SEvan.Yan@Sun.COM 	addition.pci_size_hi = 0;
337110923SEvan.Yan@Sun.COM 	addition.pci_size_low = size;
337210923SEvan.Yan@Sun.COM 
337310923SEvan.Yan@Sun.COM 	DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
337410923SEvan.Yan@Sun.COM 
337510923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)reg, rlen);
337610923SEvan.Yan@Sun.COM 
337710923SEvan.Yan@Sun.COM 	return (pcicfg_update_assigned_prop(dip, &addition));
337810923SEvan.Yan@Sun.COM }
337910923SEvan.Yan@Sun.COM 
338010923SEvan.Yan@Sun.COM static void
pcicfg_device_on(ddi_acc_handle_t config_handle)338110923SEvan.Yan@Sun.COM pcicfg_device_on(ddi_acc_handle_t config_handle)
338210923SEvan.Yan@Sun.COM {
338310923SEvan.Yan@Sun.COM 	/*
338410923SEvan.Yan@Sun.COM 	 * Enable memory, IO, and bus mastership
338510923SEvan.Yan@Sun.COM 	 * XXX should we enable parity, SERR#,
338610923SEvan.Yan@Sun.COM 	 * fast back-to-back, and addr. stepping?
338710923SEvan.Yan@Sun.COM 	 */
338810923SEvan.Yan@Sun.COM 	pci_config_put16(config_handle, PCI_CONF_COMM,
338910923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
339010923SEvan.Yan@Sun.COM }
339110923SEvan.Yan@Sun.COM 
339210923SEvan.Yan@Sun.COM static void
pcicfg_device_off(ddi_acc_handle_t config_handle)339310923SEvan.Yan@Sun.COM pcicfg_device_off(ddi_acc_handle_t config_handle)
339410923SEvan.Yan@Sun.COM {
339510923SEvan.Yan@Sun.COM 	/*
339610923SEvan.Yan@Sun.COM 	 * Disable I/O and memory traffic through the bridge
339710923SEvan.Yan@Sun.COM 	 */
339810923SEvan.Yan@Sun.COM 	pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
339910923SEvan.Yan@Sun.COM }
340010923SEvan.Yan@Sun.COM 
340110923SEvan.Yan@Sun.COM /*
340210923SEvan.Yan@Sun.COM  * Setup the basic 1275 properties based on information found in the config
340310923SEvan.Yan@Sun.COM  * header of the PCI device
340410923SEvan.Yan@Sun.COM  */
340510923SEvan.Yan@Sun.COM static int
pcicfg_set_standard_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)340610923SEvan.Yan@Sun.COM pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
340710923SEvan.Yan@Sun.COM 	uint8_t pcie_dev)
340810923SEvan.Yan@Sun.COM {
340910923SEvan.Yan@Sun.COM 	int ret;
341010923SEvan.Yan@Sun.COM 	uint16_t val, cap_ptr;
341110923SEvan.Yan@Sun.COM 	uint32_t wordval;
341210923SEvan.Yan@Sun.COM 	uint8_t byteval;
341310923SEvan.Yan@Sun.COM 
341410923SEvan.Yan@Sun.COM 	/* These two exists only for non-bridges */
341510923SEvan.Yan@Sun.COM 	if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
341610923SEvan.Yan@Sun.COM 	    & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
341710923SEvan.Yan@Sun.COM 		byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
341810923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
341910923SEvan.Yan@Sun.COM 		    "min-grant", byteval)) != DDI_SUCCESS) {
342010923SEvan.Yan@Sun.COM 			return (ret);
342110923SEvan.Yan@Sun.COM 		}
342210923SEvan.Yan@Sun.COM 
342310923SEvan.Yan@Sun.COM 		byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
342410923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
342510923SEvan.Yan@Sun.COM 		    "max-latency", byteval)) != DDI_SUCCESS) {
342610923SEvan.Yan@Sun.COM 			return (ret);
342710923SEvan.Yan@Sun.COM 		}
342810923SEvan.Yan@Sun.COM 	}
342910923SEvan.Yan@Sun.COM 
343010923SEvan.Yan@Sun.COM 	/*
343110923SEvan.Yan@Sun.COM 	 * These should always exist and have the value of the
343210923SEvan.Yan@Sun.COM 	 * corresponding register value
343310923SEvan.Yan@Sun.COM 	 */
343410923SEvan.Yan@Sun.COM 	val = pci_config_get16(config_handle, PCI_CONF_VENID);
343510923SEvan.Yan@Sun.COM 
343610923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
343710923SEvan.Yan@Sun.COM 	    "vendor-id", val)) != DDI_SUCCESS) {
343810923SEvan.Yan@Sun.COM 		return (ret);
343910923SEvan.Yan@Sun.COM 	}
344010923SEvan.Yan@Sun.COM 	val = pci_config_get16(config_handle, PCI_CONF_DEVID);
344110923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
344210923SEvan.Yan@Sun.COM 	    "device-id", val)) != DDI_SUCCESS) {
344310923SEvan.Yan@Sun.COM 		return (ret);
344410923SEvan.Yan@Sun.COM 	}
344510923SEvan.Yan@Sun.COM 	byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
344610923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
344710923SEvan.Yan@Sun.COM 	    "revision-id", byteval)) != DDI_SUCCESS) {
344810923SEvan.Yan@Sun.COM 		return (ret);
344910923SEvan.Yan@Sun.COM 	}
345010923SEvan.Yan@Sun.COM 
345110923SEvan.Yan@Sun.COM 	wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
345210923SEvan.Yan@Sun.COM 	    (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
345310923SEvan.Yan@Sun.COM 
345410923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
345510923SEvan.Yan@Sun.COM 	    "class-code", wordval)) != DDI_SUCCESS) {
345610923SEvan.Yan@Sun.COM 		return (ret);
345710923SEvan.Yan@Sun.COM 	}
345810923SEvan.Yan@Sun.COM 	/* devsel-speed starts at the 9th bit */
345910923SEvan.Yan@Sun.COM 	val = (pci_config_get16(config_handle,
346010923SEvan.Yan@Sun.COM 	    PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9;
346110923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
346210923SEvan.Yan@Sun.COM 	    "devsel-speed", val)) != DDI_SUCCESS) {
346310923SEvan.Yan@Sun.COM 		return (ret);
346410923SEvan.Yan@Sun.COM 	}
346510923SEvan.Yan@Sun.COM 
346610923SEvan.Yan@Sun.COM 	/*
346710923SEvan.Yan@Sun.COM 	 * The next three are bits set in the status register.  The property is
346810923SEvan.Yan@Sun.COM 	 * present (but with no value other than its own existence) if the bit
346910923SEvan.Yan@Sun.COM 	 * is set, non-existent otherwise
347010923SEvan.Yan@Sun.COM 	 */
347110923SEvan.Yan@Sun.COM 	if ((!pcie_dev) &&
347210923SEvan.Yan@Sun.COM 	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
347310923SEvan.Yan@Sun.COM 	    PCI_STAT_FBBC)) {
347410923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
347510923SEvan.Yan@Sun.COM 		    "fast-back-to-back", 0)) != DDI_SUCCESS) {
347610923SEvan.Yan@Sun.COM 			return (ret);
347710923SEvan.Yan@Sun.COM 		}
347810923SEvan.Yan@Sun.COM 	}
347910923SEvan.Yan@Sun.COM 	if ((!pcie_dev) &&
348010923SEvan.Yan@Sun.COM 	    (pci_config_get16(config_handle, PCI_CONF_STAT) &
348110923SEvan.Yan@Sun.COM 	    PCI_STAT_66MHZ)) {
348210923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
348310923SEvan.Yan@Sun.COM 		    "66mhz-capable", 0)) != DDI_SUCCESS) {
348410923SEvan.Yan@Sun.COM 			return (ret);
348510923SEvan.Yan@Sun.COM 		}
348610923SEvan.Yan@Sun.COM 	}
348710923SEvan.Yan@Sun.COM 	if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
348810923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
348910923SEvan.Yan@Sun.COM 		    "udf-supported", 0)) != DDI_SUCCESS) {
349010923SEvan.Yan@Sun.COM 			return (ret);
349110923SEvan.Yan@Sun.COM 		}
349210923SEvan.Yan@Sun.COM 	}
349310923SEvan.Yan@Sun.COM 
349410923SEvan.Yan@Sun.COM 	/*
349510923SEvan.Yan@Sun.COM 	 * These next three are optional and are not present
349610923SEvan.Yan@Sun.COM 	 * if the corresponding register is zero.  If the value
349710923SEvan.Yan@Sun.COM 	 * is non-zero then the property exists with the value
349810923SEvan.Yan@Sun.COM 	 * of the register.
349910923SEvan.Yan@Sun.COM 	 */
350010923SEvan.Yan@Sun.COM 	if ((val = pci_config_get16(config_handle,
350110923SEvan.Yan@Sun.COM 	    PCI_CONF_SUBVENID)) != 0) {
350210923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
350310923SEvan.Yan@Sun.COM 		    "subsystem-vendor-id", val)) != DDI_SUCCESS) {
350410923SEvan.Yan@Sun.COM 			return (ret);
350510923SEvan.Yan@Sun.COM 		}
350610923SEvan.Yan@Sun.COM 	}
350710923SEvan.Yan@Sun.COM 	if ((val = pci_config_get16(config_handle,
350810923SEvan.Yan@Sun.COM 	    PCI_CONF_SUBSYSID)) != 0) {
350910923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
351010923SEvan.Yan@Sun.COM 		    "subsystem-id", val)) != DDI_SUCCESS) {
351110923SEvan.Yan@Sun.COM 			return (ret);
351210923SEvan.Yan@Sun.COM 		}
351310923SEvan.Yan@Sun.COM 	}
351410923SEvan.Yan@Sun.COM 	if ((val = pci_config_get16(config_handle,
351510923SEvan.Yan@Sun.COM 	    PCI_CONF_CACHE_LINESZ)) != 0) {
351610923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
351710923SEvan.Yan@Sun.COM 		    "cache-line-size", val)) != DDI_SUCCESS) {
351810923SEvan.Yan@Sun.COM 			return (ret);
351910923SEvan.Yan@Sun.COM 		}
352010923SEvan.Yan@Sun.COM 	}
352110923SEvan.Yan@Sun.COM 
352210923SEvan.Yan@Sun.COM 	/*
352310923SEvan.Yan@Sun.COM 	 * If the Interrupt Pin register is non-zero then the
352410923SEvan.Yan@Sun.COM 	 * interrupts property exists
352510923SEvan.Yan@Sun.COM 	 */
352610923SEvan.Yan@Sun.COM 	if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
352710923SEvan.Yan@Sun.COM 		/*
352810923SEvan.Yan@Sun.COM 		 * If interrupt pin is non-zero,
352910923SEvan.Yan@Sun.COM 		 * record the interrupt line used
353010923SEvan.Yan@Sun.COM 		 */
353110923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
353210923SEvan.Yan@Sun.COM 		    "interrupts", byteval)) != DDI_SUCCESS) {
353310923SEvan.Yan@Sun.COM 			return (ret);
353410923SEvan.Yan@Sun.COM 		}
353510923SEvan.Yan@Sun.COM 	}
353610923SEvan.Yan@Sun.COM 
353710923SEvan.Yan@Sun.COM 	ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr);
353810923SEvan.Yan@Sun.COM 
353910923SEvan.Yan@Sun.COM 	if (pcie_dev && (ret == DDI_SUCCESS)) {
354010923SEvan.Yan@Sun.COM 		val = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
354110923SEvan.Yan@Sun.COM 		    PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
354210923SEvan.Yan@Sun.COM 		/* if slot implemented, get physical slot number */
354310923SEvan.Yan@Sun.COM 		if (val) {
354410923SEvan.Yan@Sun.COM 			wordval = (PCI_CAP_GET32(config_handle, NULL,
354510923SEvan.Yan@Sun.COM 			    cap_ptr, PCIE_SLOTCAP) >>
354610923SEvan.Yan@Sun.COM 			    PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) &
354710923SEvan.Yan@Sun.COM 			    PCIE_SLOTCAP_PHY_SLOT_NUM_MASK;
354810923SEvan.Yan@Sun.COM 			if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE,
354910923SEvan.Yan@Sun.COM 			    dip, "physical-slot#", wordval))
355010923SEvan.Yan@Sun.COM 			    != DDI_SUCCESS) {
355110923SEvan.Yan@Sun.COM 				return (ret);
355210923SEvan.Yan@Sun.COM 			}
355310923SEvan.Yan@Sun.COM 		}
355410923SEvan.Yan@Sun.COM 	}
355510923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
355610923SEvan.Yan@Sun.COM }
355710923SEvan.Yan@Sun.COM static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type,int pbus,int sbus)355810923SEvan.Yan@Sun.COM pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type,
355910923SEvan.Yan@Sun.COM     int pbus, int sbus)
356010923SEvan.Yan@Sun.COM {
356110923SEvan.Yan@Sun.COM 	int ret;
356210923SEvan.Yan@Sun.COM 	char device_type[8];
356310923SEvan.Yan@Sun.COM 
356410923SEvan.Yan@Sun.COM 	if (pcie_device_type)
356510923SEvan.Yan@Sun.COM 		(void) strcpy(device_type, "pciex");
356610923SEvan.Yan@Sun.COM 	else
356710923SEvan.Yan@Sun.COM 		(void) strcpy(device_type, "pci");
356810923SEvan.Yan@Sun.COM 
356910923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
357010923SEvan.Yan@Sun.COM 	    "device_type", device_type)) != DDI_SUCCESS) {
357110923SEvan.Yan@Sun.COM 		return (ret);
357210923SEvan.Yan@Sun.COM 	}
357310923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
357410923SEvan.Yan@Sun.COM 	    "#address-cells", 3)) != DDI_SUCCESS) {
357510923SEvan.Yan@Sun.COM 		return (ret);
357610923SEvan.Yan@Sun.COM 	}
357710923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
357810923SEvan.Yan@Sun.COM 	    "#size-cells", 2)) != DDI_SUCCESS) {
357910923SEvan.Yan@Sun.COM 		return (ret);
358010923SEvan.Yan@Sun.COM 	}
358110923SEvan.Yan@Sun.COM 
358210923SEvan.Yan@Sun.COM 	/*
358310923SEvan.Yan@Sun.COM 	 * Create primary-bus and secondary-bus properties to be used
358410923SEvan.Yan@Sun.COM 	 * to restore bus numbers in the pcicfg_setup_bridge() routine.
358510923SEvan.Yan@Sun.COM 	 */
358610923SEvan.Yan@Sun.COM 	if (pbus != -1 && sbus != -1) {
358710923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
358810923SEvan.Yan@Sun.COM 		    "primary-bus", pbus)) != DDI_SUCCESS) {
358910923SEvan.Yan@Sun.COM 				return (ret);
359010923SEvan.Yan@Sun.COM 		}
359110923SEvan.Yan@Sun.COM 		if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
359210923SEvan.Yan@Sun.COM 		    "secondary-bus", sbus)) != DDI_SUCCESS) {
359310923SEvan.Yan@Sun.COM 				return (ret);
359410923SEvan.Yan@Sun.COM 		}
359510923SEvan.Yan@Sun.COM 	}
359610923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
359710923SEvan.Yan@Sun.COM }
359810923SEvan.Yan@Sun.COM 
359910923SEvan.Yan@Sun.COM static int
pcicfg_set_childnode_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)360010923SEvan.Yan@Sun.COM pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
360110923SEvan.Yan@Sun.COM 	uint8_t pcie_dev)
360210923SEvan.Yan@Sun.COM {
360310923SEvan.Yan@Sun.COM 
360410923SEvan.Yan@Sun.COM 	int		ret;
360510923SEvan.Yan@Sun.COM 	char		*name;
360610923SEvan.Yan@Sun.COM 	char		buffer[64], pprefix[8];
360710923SEvan.Yan@Sun.COM 	uint16_t	classcode;
360810923SEvan.Yan@Sun.COM 	uint8_t		revid, pif, pclass, psubclass;
360910923SEvan.Yan@Sun.COM 	char		*compat[24];
361010923SEvan.Yan@Sun.COM 	int		i;
361110923SEvan.Yan@Sun.COM 	int		n;
361210923SEvan.Yan@Sun.COM 	uint16_t		sub_vid, sub_sid, vid, did;
361310923SEvan.Yan@Sun.COM 
361410923SEvan.Yan@Sun.COM 	/* set the property prefix based on the device type */
361510923SEvan.Yan@Sun.COM 	if (pcie_dev)
361610923SEvan.Yan@Sun.COM 		(void) sprintf(pprefix, "pciex");
361710923SEvan.Yan@Sun.COM 	else
361810923SEvan.Yan@Sun.COM 		(void) sprintf(pprefix, "pci");
361910923SEvan.Yan@Sun.COM 	sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
362010923SEvan.Yan@Sun.COM 	sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
362110923SEvan.Yan@Sun.COM 	vid = pci_config_get16(config_handle, PCI_CONF_VENID);
362210923SEvan.Yan@Sun.COM 	did = pci_config_get16(config_handle, PCI_CONF_DEVID);
362310923SEvan.Yan@Sun.COM 	revid = pci_config_get8(config_handle, PCI_CONF_REVID);
362410923SEvan.Yan@Sun.COM 	pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
362510923SEvan.Yan@Sun.COM 	classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
362610923SEvan.Yan@Sun.COM 	pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
362710923SEvan.Yan@Sun.COM 	psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
362810923SEvan.Yan@Sun.COM 
362910923SEvan.Yan@Sun.COM 	/*
363010923SEvan.Yan@Sun.COM 	 * NOTE: These are for both a child and PCI-PCI bridge node
363110923SEvan.Yan@Sun.COM 	 */
363210923SEvan.Yan@Sun.COM 
363310923SEvan.Yan@Sun.COM 	/*
363410923SEvan.Yan@Sun.COM 	 *	"name" property rule
363510923SEvan.Yan@Sun.COM 	 *	--------------------
363610923SEvan.Yan@Sun.COM 	 *
363710923SEvan.Yan@Sun.COM 	 *
363810923SEvan.Yan@Sun.COM 	 * |	  \svid |
363910923SEvan.Yan@Sun.COM 	 * |	   \    |
364010923SEvan.Yan@Sun.COM 	 * |	    \   |
364110923SEvan.Yan@Sun.COM 	 * |	ssid \  |	=0		|	!= 0		|
364210923SEvan.Yan@Sun.COM 	 * |------------|-----------------------|-----------------------|
364310923SEvan.Yan@Sun.COM 	 * |		|			|			|
364410923SEvan.Yan@Sun.COM 	 * |	=0	|	vid,did		|	svid,ssid	|
364510923SEvan.Yan@Sun.COM 	 * |		|			|			|
364610923SEvan.Yan@Sun.COM 	 * |------------|-----------------------|-----------------------|
364710923SEvan.Yan@Sun.COM 	 * |		|			|			|
364810923SEvan.Yan@Sun.COM 	 * |	!=0	|	svid,ssid	|	svid,ssid	|
364910923SEvan.Yan@Sun.COM 	 * |		|			|			|
365010923SEvan.Yan@Sun.COM 	 * |------------|-----------------------|-----------------------|
365110923SEvan.Yan@Sun.COM 	 *
365210923SEvan.Yan@Sun.COM 	 * where:
365310923SEvan.Yan@Sun.COM 	 *    vid = vendor id
365410923SEvan.Yan@Sun.COM 	 *    did = device id
365510923SEvan.Yan@Sun.COM 	 *   svid = subsystem vendor id
365610923SEvan.Yan@Sun.COM 	 *   ssid = subsystem id
365710923SEvan.Yan@Sun.COM 	 */
365810923SEvan.Yan@Sun.COM 
365910923SEvan.Yan@Sun.COM 	if ((sub_sid != 0) || (sub_vid != 0)) {
366010923SEvan.Yan@Sun.COM 		(void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid);
366110923SEvan.Yan@Sun.COM 	} else {
366210923SEvan.Yan@Sun.COM 		(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
366310923SEvan.Yan@Sun.COM 	}
366410923SEvan.Yan@Sun.COM 
366510923SEvan.Yan@Sun.COM 	/*
366610923SEvan.Yan@Sun.COM 	 * In some environments, trying to use "generic" 1275 names is
366710923SEvan.Yan@Sun.COM 	 * not the convention.  In those cases use the name as created
366810923SEvan.Yan@Sun.COM 	 * above.  In all the rest of the cases, check to see if there
366910923SEvan.Yan@Sun.COM 	 * is a generic name first.
367010923SEvan.Yan@Sun.COM 	 */
367110923SEvan.Yan@Sun.COM #ifdef _DONT_USE_1275_GENERIC_NAMES
367210923SEvan.Yan@Sun.COM 	name = buffer;
367310923SEvan.Yan@Sun.COM #else
367410923SEvan.Yan@Sun.COM 	if ((name = pcicfg_get_class_name(classcode)) == NULL) {
367510923SEvan.Yan@Sun.COM 		/*
367610923SEvan.Yan@Sun.COM 		 * Set name to the above fabricated name
367710923SEvan.Yan@Sun.COM 		 */
367810923SEvan.Yan@Sun.COM 		name = buffer;
367910923SEvan.Yan@Sun.COM 	}
368010923SEvan.Yan@Sun.COM #endif
368110923SEvan.Yan@Sun.COM 
368210923SEvan.Yan@Sun.COM 	/*
368310923SEvan.Yan@Sun.COM 	 * The node name field needs to be filled in with the name
368410923SEvan.Yan@Sun.COM 	 */
368510923SEvan.Yan@Sun.COM 	if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
368610923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set nodename for node\n");
368710923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
368810923SEvan.Yan@Sun.COM 	}
368910923SEvan.Yan@Sun.COM 
369010923SEvan.Yan@Sun.COM 	/*
369110923SEvan.Yan@Sun.COM 	 * Create the compatible property as an array of pointers
369210923SEvan.Yan@Sun.COM 	 * to strings.  Start with the buffer created above.
369310923SEvan.Yan@Sun.COM 	 */
369410923SEvan.Yan@Sun.COM 	n = 0;
369510923SEvan.Yan@Sun.COM 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
369610923SEvan.Yan@Sun.COM 	(void) strcpy(compat[n++], buffer);
369710923SEvan.Yan@Sun.COM 
369810923SEvan.Yan@Sun.COM 	/*
369910923SEvan.Yan@Sun.COM 	 * Setup 'compatible' as per the PCI2.1 bindings document.
370010923SEvan.Yan@Sun.COM 	 *	pci[ex]VVVV,DDDD.SSSS.ssss.RR
370110923SEvan.Yan@Sun.COM 	 *	pci[ex]VVVV,DDDD.SSSS.ssss
370210923SEvan.Yan@Sun.COM 	 *	pciSSSS.ssss  -> not created for PCIe as per PCIe bindings
370310923SEvan.Yan@Sun.COM 	 *	pci[ex]VVVV,DDDD.RR
370410923SEvan.Yan@Sun.COM 	 *	pci[ex]VVVV,DDDD
370510923SEvan.Yan@Sun.COM 	 *	pci[ex]class,CCSSPP
370610923SEvan.Yan@Sun.COM 	 *	pci[ex]class,CCSS
370710923SEvan.Yan@Sun.COM 	 */
370810923SEvan.Yan@Sun.COM 
370910923SEvan.Yan@Sun.COM 	/* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
371010923SEvan.Yan@Sun.COM 	(void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix,  vid, did,
371110923SEvan.Yan@Sun.COM 	    sub_vid, sub_sid, revid);
371210923SEvan.Yan@Sun.COM 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
371310923SEvan.Yan@Sun.COM 	(void) strcpy(compat[n++], buffer);
371410923SEvan.Yan@Sun.COM 
371510923SEvan.Yan@Sun.COM 	/* pci[ex]VVVV,DDDD.SSSS.ssss */
371610923SEvan.Yan@Sun.COM 	(void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix,  vid, did,
371710923SEvan.Yan@Sun.COM 	    sub_vid, sub_sid);
371810923SEvan.Yan@Sun.COM 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
371910923SEvan.Yan@Sun.COM 	(void) strcpy(compat[n++], buffer);
372010923SEvan.Yan@Sun.COM 
372110923SEvan.Yan@Sun.COM 	/* pciSSSS.ssss  -> not created for PCIe as per PCIe bindings */
372210923SEvan.Yan@Sun.COM 	if (!pcie_dev) {
372310923SEvan.Yan@Sun.COM 		(void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
372410923SEvan.Yan@Sun.COM 		compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
372510923SEvan.Yan@Sun.COM 		(void) strcpy(compat[n++], buffer);
372610923SEvan.Yan@Sun.COM 	}
372710923SEvan.Yan@Sun.COM 
372810923SEvan.Yan@Sun.COM 	/* pci[ex]VVVV,DDDD.RR */
372910923SEvan.Yan@Sun.COM 	(void) sprintf(buffer, "%s%x,%x.%x", pprefix,  vid, did, revid);
373010923SEvan.Yan@Sun.COM 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
373110923SEvan.Yan@Sun.COM 	(void) strcpy(compat[n++], buffer);
373210923SEvan.Yan@Sun.COM 
373310923SEvan.Yan@Sun.COM 	/* pci[ex]VVVV,DDDD */
373410923SEvan.Yan@Sun.COM 	(void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
373510923SEvan.Yan@Sun.COM 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
373610923SEvan.Yan@Sun.COM 	(void) strcpy(compat[n++], buffer);
373710923SEvan.Yan@Sun.COM 
373810923SEvan.Yan@Sun.COM 	/* pci[ex]class,CCSSPP */
373910923SEvan.Yan@Sun.COM 	(void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
374010923SEvan.Yan@Sun.COM 	    pclass, psubclass, pif);
374110923SEvan.Yan@Sun.COM 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
374210923SEvan.Yan@Sun.COM 	(void) strcpy(compat[n++], buffer);
374310923SEvan.Yan@Sun.COM 
374410923SEvan.Yan@Sun.COM 	/* pci[ex]class,CCSS */
374510923SEvan.Yan@Sun.COM 	(void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
374610923SEvan.Yan@Sun.COM 	compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
374710923SEvan.Yan@Sun.COM 	(void) strcpy(compat[n++], buffer);
374810923SEvan.Yan@Sun.COM 
374910923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
375010923SEvan.Yan@Sun.COM 	    "compatible", (char **)compat, n)) != DDI_SUCCESS) {
375110923SEvan.Yan@Sun.COM 		return (ret);
375210923SEvan.Yan@Sun.COM 	}
375310923SEvan.Yan@Sun.COM 
375410923SEvan.Yan@Sun.COM 	for (i = 0; i < n; i++) {
375510923SEvan.Yan@Sun.COM 		kmem_free(compat[i], strlen(compat[i]) + 1);
375610923SEvan.Yan@Sun.COM 	}
375710923SEvan.Yan@Sun.COM 
375810923SEvan.Yan@Sun.COM 	DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name);
375910923SEvan.Yan@Sun.COM 	if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
376010923SEvan.Yan@Sun.COM 	    "name", name)) != DDI_SUCCESS) {
376110923SEvan.Yan@Sun.COM 
376210923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_set_childnode_props - Unable to create name "
376310923SEvan.Yan@Sun.COM 		    "property\n");
376410923SEvan.Yan@Sun.COM 
376510923SEvan.Yan@Sun.COM 		return (ret);
376610923SEvan.Yan@Sun.COM 	}
376710923SEvan.Yan@Sun.COM 
376810923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
376910923SEvan.Yan@Sun.COM }
377010923SEvan.Yan@Sun.COM 
377110923SEvan.Yan@Sun.COM /*
377210923SEvan.Yan@Sun.COM  * Program the bus numbers into the bridge
377310923SEvan.Yan@Sun.COM  */
377410923SEvan.Yan@Sun.COM 
377510923SEvan.Yan@Sun.COM static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,uint_t primary,uint_t secondary,uint_t subordinate)377610923SEvan.Yan@Sun.COM pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
377710923SEvan.Yan@Sun.COM uint_t primary, uint_t secondary, uint_t subordinate)
377810923SEvan.Yan@Sun.COM {
377910923SEvan.Yan@Sun.COM 	DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
378010923SEvan.Yan@Sun.COM 	    subordinate);
378110923SEvan.Yan@Sun.COM 	/*
378210923SEvan.Yan@Sun.COM 	 * Primary bus#
378310923SEvan.Yan@Sun.COM 	 */
378410923SEvan.Yan@Sun.COM 	pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
378510923SEvan.Yan@Sun.COM 
378610923SEvan.Yan@Sun.COM 	/*
378710923SEvan.Yan@Sun.COM 	 * Secondary bus#
378810923SEvan.Yan@Sun.COM 	 */
378910923SEvan.Yan@Sun.COM 	pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
379010923SEvan.Yan@Sun.COM 
379110923SEvan.Yan@Sun.COM 	/*
379210923SEvan.Yan@Sun.COM 	 * Subordinate bus#
379310923SEvan.Yan@Sun.COM 	 */
379410923SEvan.Yan@Sun.COM 	pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
379510923SEvan.Yan@Sun.COM }
379610923SEvan.Yan@Sun.COM 
379710923SEvan.Yan@Sun.COM /*
379810923SEvan.Yan@Sun.COM  * Put bridge registers into initial state
379910923SEvan.Yan@Sun.COM  */
380010923SEvan.Yan@Sun.COM static void
pcicfg_setup_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle,dev_info_t * dip)380110923SEvan.Yan@Sun.COM pcicfg_setup_bridge(pcicfg_phdl_t *entry,
380210923SEvan.Yan@Sun.COM     ddi_acc_handle_t handle, dev_info_t *dip)
380310923SEvan.Yan@Sun.COM {
380410923SEvan.Yan@Sun.COM 	int pbus, sbus;
380510923SEvan.Yan@Sun.COM 
380610923SEvan.Yan@Sun.COM 	/*
380710923SEvan.Yan@Sun.COM 	 * The highest bus seen during probing is the max-subordinate bus
380810923SEvan.Yan@Sun.COM 	 */
380910923SEvan.Yan@Sun.COM 	pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
381010923SEvan.Yan@Sun.COM 
381110923SEvan.Yan@Sun.COM 
381210923SEvan.Yan@Sun.COM 	/*
381310923SEvan.Yan@Sun.COM 	 * If there exists more than 1 downstream bridge, it
381410923SEvan.Yan@Sun.COM 	 * will be reset by the below secondary bus reset which
381510923SEvan.Yan@Sun.COM 	 * will clear the bus numbers assumed to be programmed in
381610923SEvan.Yan@Sun.COM 	 * the pcicfg_probe_children() routine.  We therefore restore
381710923SEvan.Yan@Sun.COM 	 * them here.
381810923SEvan.Yan@Sun.COM 	 */
381910923SEvan.Yan@Sun.COM 	if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) {
382010923SEvan.Yan@Sun.COM 		pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
382110923SEvan.Yan@Sun.COM 		    DDI_PROP_DONTPASS, "primary-bus", -1);
382210923SEvan.Yan@Sun.COM 		sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
382310923SEvan.Yan@Sun.COM 		    DDI_PROP_DONTPASS, "secondary-bus", -1);
382410923SEvan.Yan@Sun.COM 		if (pbus != -1 && sbus != -1) {
382510923SEvan.Yan@Sun.COM 			pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus);
382610923SEvan.Yan@Sun.COM 			pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus);
382710923SEvan.Yan@Sun.COM 		} else {
382810923SEvan.Yan@Sun.COM 			cmn_err(CE_WARN, "Invalid Bridge number detected: \
382910923SEvan.Yan@Sun.COM 			    %s%d: pbus = 0x%x, sbus = 0x%x",
383010923SEvan.Yan@Sun.COM 			    ddi_get_name(dip), ddi_get_instance(dip), pbus,
383110923SEvan.Yan@Sun.COM 			    sbus);
383210923SEvan.Yan@Sun.COM 		}
383310923SEvan.Yan@Sun.COM 	}
383410923SEvan.Yan@Sun.COM 
383510923SEvan.Yan@Sun.COM 	/*
383610923SEvan.Yan@Sun.COM 	 * Reset the secondary bus
383710923SEvan.Yan@Sun.COM 	 */
383810923SEvan.Yan@Sun.COM 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
383910923SEvan.Yan@Sun.COM 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
384010923SEvan.Yan@Sun.COM 
384110923SEvan.Yan@Sun.COM 	drv_usecwait(100);
384210923SEvan.Yan@Sun.COM 
384310923SEvan.Yan@Sun.COM 	pci_config_put16(handle, PCI_BCNF_BCNTRL,
384410923SEvan.Yan@Sun.COM 	    pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
384510923SEvan.Yan@Sun.COM 
384610923SEvan.Yan@Sun.COM 	/*
384710923SEvan.Yan@Sun.COM 	 * Program the memory base register with the
384810923SEvan.Yan@Sun.COM 	 * start of the memory range
384910923SEvan.Yan@Sun.COM 	 */
385010923SEvan.Yan@Sun.COM 	pci_config_put16(handle, PCI_BCNF_MEM_BASE,
385110923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
385210923SEvan.Yan@Sun.COM 
385310923SEvan.Yan@Sun.COM 	/*
385410923SEvan.Yan@Sun.COM 	 * Program the I/O base register with the start of the I/O range
385510923SEvan.Yan@Sun.COM 	 */
385610923SEvan.Yan@Sun.COM 	pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
385710923SEvan.Yan@Sun.COM 	    PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
385810923SEvan.Yan@Sun.COM 	pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
385910923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
386010923SEvan.Yan@Sun.COM 
386110923SEvan.Yan@Sun.COM 	/*
386210923SEvan.Yan@Sun.COM 	 * Clear status bits
386310923SEvan.Yan@Sun.COM 	 */
386410923SEvan.Yan@Sun.COM 	pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
386510923SEvan.Yan@Sun.COM 
386610923SEvan.Yan@Sun.COM 	/*
386710923SEvan.Yan@Sun.COM 	 * Turn off prefetchable range
386810923SEvan.Yan@Sun.COM 	 */
386910923SEvan.Yan@Sun.COM 	pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
387010923SEvan.Yan@Sun.COM 	pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
387110923SEvan.Yan@Sun.COM 	pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
387210923SEvan.Yan@Sun.COM 
387310923SEvan.Yan@Sun.COM 	/*
387410923SEvan.Yan@Sun.COM 	 * Needs to be set to this value
387510923SEvan.Yan@Sun.COM 	 */
387610923SEvan.Yan@Sun.COM 	pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
387710923SEvan.Yan@Sun.COM 
387810923SEvan.Yan@Sun.COM 	/*
387910923SEvan.Yan@Sun.COM 	 * After a Reset, we need to wait 2^25 clock cycles before the
388010923SEvan.Yan@Sun.COM 	 * first Configuration access.  The worst case is 33MHz, which
388110923SEvan.Yan@Sun.COM 	 * is a 1 second wait.
388210923SEvan.Yan@Sun.COM 	 */
388310923SEvan.Yan@Sun.COM 	drv_usecwait(pcicfg_sec_reset_delay);
388410923SEvan.Yan@Sun.COM 
388510923SEvan.Yan@Sun.COM }
388610923SEvan.Yan@Sun.COM 
388710923SEvan.Yan@Sun.COM static void
pcicfg_update_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)388810923SEvan.Yan@Sun.COM pcicfg_update_bridge(pcicfg_phdl_t *entry,
388910923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle)
389010923SEvan.Yan@Sun.COM {
389110923SEvan.Yan@Sun.COM 	uint_t length;
389210923SEvan.Yan@Sun.COM 
389310923SEvan.Yan@Sun.COM 	/*
389410923SEvan.Yan@Sun.COM 	 * Program the memory limit register with the end of the memory range
389510923SEvan.Yan@Sun.COM 	 */
389610923SEvan.Yan@Sun.COM 
389710923SEvan.Yan@Sun.COM 	DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
389810923SEvan.Yan@Sun.COM 	    PCICFG_ROUND_DOWN(entry->memory_last,
389910923SEvan.Yan@Sun.COM 	    PCICFG_MEMGRAN));
390010923SEvan.Yan@Sun.COM 
390110923SEvan.Yan@Sun.COM 	pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
390210923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(
390310923SEvan.Yan@Sun.COM 	    PCICFG_ROUND_DOWN(entry->memory_last,
390410923SEvan.Yan@Sun.COM 	    PCICFG_MEMGRAN))));
390510923SEvan.Yan@Sun.COM 	/*
390610923SEvan.Yan@Sun.COM 	 * Since this is a bridge, the rest of this range will
390710923SEvan.Yan@Sun.COM 	 * be responded to by the bridge.  We have to round up
390810923SEvan.Yan@Sun.COM 	 * so no other device claims it.
390910923SEvan.Yan@Sun.COM 	 */
391010923SEvan.Yan@Sun.COM 	if ((length = (PCICFG_ROUND_UP(entry->memory_last,
391110923SEvan.Yan@Sun.COM 	    PCICFG_MEMGRAN) - entry->memory_last)) > 0) {
391210923SEvan.Yan@Sun.COM 		(void) pcicfg_get_mem(entry, length, NULL);
391310923SEvan.Yan@Sun.COM 		DEBUG1("Added [0x%x]at the top of "
391410923SEvan.Yan@Sun.COM 		    "the bridge (mem)\n", length);
391510923SEvan.Yan@Sun.COM 	}
391610923SEvan.Yan@Sun.COM 
391710923SEvan.Yan@Sun.COM 	/*
391810923SEvan.Yan@Sun.COM 	 * Program the I/O limit register with the end of the I/O range
391910923SEvan.Yan@Sun.COM 	 */
392010923SEvan.Yan@Sun.COM 	pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
392110923SEvan.Yan@Sun.COM 	    PCICFG_HIBYTE(PCICFG_LOWORD(
392210923SEvan.Yan@Sun.COM 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
392310923SEvan.Yan@Sun.COM 	    PCICFG_IOGRAN)))));
392410923SEvan.Yan@Sun.COM 
392510923SEvan.Yan@Sun.COM 	pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
392610923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
392710923SEvan.Yan@Sun.COM 	    PCICFG_IOGRAN))));
392810923SEvan.Yan@Sun.COM 
392910923SEvan.Yan@Sun.COM 	/*
393010923SEvan.Yan@Sun.COM 	 * Same as above for I/O space. Since this is a
393110923SEvan.Yan@Sun.COM 	 * bridge, the rest of this range will be responded
393210923SEvan.Yan@Sun.COM 	 * to by the bridge.  We have to round up so no
393310923SEvan.Yan@Sun.COM 	 * other device claims it.
393410923SEvan.Yan@Sun.COM 	 */
393510923SEvan.Yan@Sun.COM 	if ((length = (PCICFG_ROUND_UP(entry->io_last,
393610923SEvan.Yan@Sun.COM 	    PCICFG_IOGRAN) - entry->io_last)) > 0) {
393710923SEvan.Yan@Sun.COM 		(void) pcicfg_get_io(entry, length, NULL);
393810923SEvan.Yan@Sun.COM 		DEBUG1("Added [0x%x]at the top of "
393910923SEvan.Yan@Sun.COM 		    "the bridge (I/O)\n",  length);
394010923SEvan.Yan@Sun.COM 	}
394110923SEvan.Yan@Sun.COM }
394210923SEvan.Yan@Sun.COM 
394310923SEvan.Yan@Sun.COM /*ARGSUSED*/
394410923SEvan.Yan@Sun.COM static void
pcicfg_disable_bridge_probe_err(dev_info_t * dip,ddi_acc_handle_t h,pcicfg_err_regs_t * regs)394510923SEvan.Yan@Sun.COM pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
394610923SEvan.Yan@Sun.COM 	pcicfg_err_regs_t *regs)
394710923SEvan.Yan@Sun.COM {
394810923SEvan.Yan@Sun.COM 	uint16_t val;
394910923SEvan.Yan@Sun.COM 
395010923SEvan.Yan@Sun.COM 	/* disable SERR generated in the context of Master Aborts. */
395110923SEvan.Yan@Sun.COM 	regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM);
395210923SEvan.Yan@Sun.COM 	val &= ~PCI_COMM_SERR_ENABLE;
395310923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_CONF_COMM, val);
395410923SEvan.Yan@Sun.COM 	regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL);
395510923SEvan.Yan@Sun.COM 	val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
395610923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_BCNTRL, val);
395710923SEvan.Yan@Sun.COM 	/* clear any current pending errors */
395810923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
395910923SEvan.Yan@Sun.COM 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
396010923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
396110923SEvan.Yan@Sun.COM 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
396210923SEvan.Yan@Sun.COM 	/* if we are a PCIe device, disable the generation of UR, CE and NFE */
396310923SEvan.Yan@Sun.COM 	if (regs->pcie_dev) {
396410923SEvan.Yan@Sun.COM 		uint16_t devctl;
396510923SEvan.Yan@Sun.COM 		uint16_t cap_ptr;
396610923SEvan.Yan@Sun.COM 
396710923SEvan.Yan@Sun.COM 		if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
396810923SEvan.Yan@Sun.COM 		    DDI_FAILURE)
396910923SEvan.Yan@Sun.COM 			return;
397010923SEvan.Yan@Sun.COM 
397110923SEvan.Yan@Sun.COM 		regs->pcie_cap_off = cap_ptr;
397210923SEvan.Yan@Sun.COM 		regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr,
397310923SEvan.Yan@Sun.COM 		    PCIE_DEVCTL);
397410923SEvan.Yan@Sun.COM 		devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN |
397510923SEvan.Yan@Sun.COM 		    PCIE_DEVCTL_CE_REPORTING_EN |
397610923SEvan.Yan@Sun.COM 		    PCIE_DEVCTL_NFE_REPORTING_EN |
397710923SEvan.Yan@Sun.COM 		    PCIE_DEVCTL_FE_REPORTING_EN);
397810923SEvan.Yan@Sun.COM 		PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl);
397910923SEvan.Yan@Sun.COM 	}
398010923SEvan.Yan@Sun.COM }
398110923SEvan.Yan@Sun.COM 
398210923SEvan.Yan@Sun.COM /*ARGSUSED*/
398310923SEvan.Yan@Sun.COM static void
pcicfg_enable_bridge_probe_err(dev_info_t * dip,ddi_acc_handle_t h,pcicfg_err_regs_t * regs)398410923SEvan.Yan@Sun.COM pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
398510923SEvan.Yan@Sun.COM 	pcicfg_err_regs_t *regs)
398610923SEvan.Yan@Sun.COM {
398710923SEvan.Yan@Sun.COM 	/* clear any pending errors */
398810923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
398910923SEvan.Yan@Sun.COM 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
399010923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
399110923SEvan.Yan@Sun.COM 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
399210923SEvan.Yan@Sun.COM 
399310923SEvan.Yan@Sun.COM 	/* restore original settings */
399410923SEvan.Yan@Sun.COM 	if (regs->pcie_dev) {
399510923SEvan.Yan@Sun.COM 		pcie_clear_errors(dip);
399610923SEvan.Yan@Sun.COM 		pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
399710923SEvan.Yan@Sun.COM 		    regs->devctl);
399810923SEvan.Yan@Sun.COM 	}
399910923SEvan.Yan@Sun.COM 
400010923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl);
400110923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_CONF_COMM, regs->cmd);
400210923SEvan.Yan@Sun.COM 
400310923SEvan.Yan@Sun.COM }
400410923SEvan.Yan@Sun.COM 
400510923SEvan.Yan@Sun.COM 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)400610923SEvan.Yan@Sun.COM pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
400711245SZhijun.Fu@Sun.COM     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
400810923SEvan.Yan@Sun.COM {
400910923SEvan.Yan@Sun.COM 	dev_info_t		*new_child;
401010923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	config_handle;
401110923SEvan.Yan@Sun.COM 	uint8_t			header_type, pcie_dev = 0;
401210923SEvan.Yan@Sun.COM 	int			ret;
401310923SEvan.Yan@Sun.COM 	pcicfg_err_regs_t	regs;
401410923SEvan.Yan@Sun.COM 
401510923SEvan.Yan@Sun.COM 	/*
401610923SEvan.Yan@Sun.COM 	 * This node will be put immediately below
401710923SEvan.Yan@Sun.COM 	 * "parent". Allocate a blank device node.  It will either
401810923SEvan.Yan@Sun.COM 	 * be filled in or freed up based on further probing.
401910923SEvan.Yan@Sun.COM 	 */
402010923SEvan.Yan@Sun.COM 	/*
402110923SEvan.Yan@Sun.COM 	 * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c
402210923SEvan.Yan@Sun.COM 	 * ndi_devi_alloc() is called as ndi_devi_alloc_sleep()
402310923SEvan.Yan@Sun.COM 	 */
402410923SEvan.Yan@Sun.COM 	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
402510923SEvan.Yan@Sun.COM 	    (pnode_t)DEVI_SID_NODEID, &new_child)
402610923SEvan.Yan@Sun.COM 	    != NDI_SUCCESS) {
402710923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n");
402810923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
402910923SEvan.Yan@Sun.COM 	}
403010923SEvan.Yan@Sun.COM 
403110923SEvan.Yan@Sun.COM 	if (pcicfg_add_config_reg(new_child, bus,
403210923SEvan.Yan@Sun.COM 	    device, func) != DDI_SUCCESS) {
403310923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_probe_children():"
403410923SEvan.Yan@Sun.COM 		    "Failed to add candidate REG\n");
403510923SEvan.Yan@Sun.COM 		goto failedconfig;
403610923SEvan.Yan@Sun.COM 	}
403710923SEvan.Yan@Sun.COM 
403810923SEvan.Yan@Sun.COM 	if ((ret = pcicfg_config_setup(new_child, &config_handle))
403910923SEvan.Yan@Sun.COM 	    != PCICFG_SUCCESS) {
404010923SEvan.Yan@Sun.COM 		if (ret == PCICFG_NODEVICE) {
404110923SEvan.Yan@Sun.COM 			(void) ndi_devi_free(new_child);
404210923SEvan.Yan@Sun.COM 			return (ret);
404310923SEvan.Yan@Sun.COM 		}
404410923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_probe_children():"
404510923SEvan.Yan@Sun.COM 		    "Failed to setup config space\n");
404610923SEvan.Yan@Sun.COM 		goto failedconfig;
404710923SEvan.Yan@Sun.COM 	}
404810923SEvan.Yan@Sun.COM 
404911245SZhijun.Fu@Sun.COM 	if (is_pcie)
405011245SZhijun.Fu@Sun.COM 		(void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
405111245SZhijun.Fu@Sun.COM 		    PCIE_BUS_INITIAL);
405211245SZhijun.Fu@Sun.COM 
405310923SEvan.Yan@Sun.COM 	/*
405410923SEvan.Yan@Sun.COM 	 * As soon as we have access to config space,
405510923SEvan.Yan@Sun.COM 	 * turn off device. It will get turned on
405610923SEvan.Yan@Sun.COM 	 * later (after memory is assigned).
405710923SEvan.Yan@Sun.COM 	 */
405810923SEvan.Yan@Sun.COM 	(void) pcicfg_device_off(config_handle);
405910923SEvan.Yan@Sun.COM 
406010923SEvan.Yan@Sun.COM 	/* check if we are PCIe device */
406110923SEvan.Yan@Sun.COM 	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
406210923SEvan.Yan@Sun.COM 	    == DDI_SUCCESS) {
406310923SEvan.Yan@Sun.COM 		DEBUG0("PCIe device detected\n");
406410923SEvan.Yan@Sun.COM 		pcie_dev = 1;
406510923SEvan.Yan@Sun.COM 	}
406610923SEvan.Yan@Sun.COM 
406710923SEvan.Yan@Sun.COM 	/*
406810923SEvan.Yan@Sun.COM 	 * Set 1275 properties common to all devices
406910923SEvan.Yan@Sun.COM 	 */
407010923SEvan.Yan@Sun.COM 	if (pcicfg_set_standard_props(new_child, config_handle,
407110923SEvan.Yan@Sun.COM 	    pcie_dev) != PCICFG_SUCCESS) {
407210923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set standard properties\n");
407310923SEvan.Yan@Sun.COM 		goto failedchild;
407410923SEvan.Yan@Sun.COM 	}
407510923SEvan.Yan@Sun.COM 
407610923SEvan.Yan@Sun.COM 	/*
407710923SEvan.Yan@Sun.COM 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
407810923SEvan.Yan@Sun.COM 	 */
407910923SEvan.Yan@Sun.COM 	if (pcicfg_set_childnode_props(new_child, config_handle,
408010923SEvan.Yan@Sun.COM 	    pcie_dev) != PCICFG_SUCCESS) {
408110923SEvan.Yan@Sun.COM 		goto failedchild;
408210923SEvan.Yan@Sun.COM 	}
408310923SEvan.Yan@Sun.COM 
408410923SEvan.Yan@Sun.COM 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
408510923SEvan.Yan@Sun.COM 
408610923SEvan.Yan@Sun.COM 	/*
408710923SEvan.Yan@Sun.COM 	 * If this is not a multi-function card only probe function zero.
408810923SEvan.Yan@Sun.COM 	 */
408910923SEvan.Yan@Sun.COM 	if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
409010923SEvan.Yan@Sun.COM 
409110923SEvan.Yan@Sun.COM 		(void) pcicfg_config_teardown(&config_handle);
409210923SEvan.Yan@Sun.COM 		(void) ndi_devi_free(new_child);
409310923SEvan.Yan@Sun.COM 		return (PCICFG_NODEVICE);
409410923SEvan.Yan@Sun.COM 	}
409510923SEvan.Yan@Sun.COM 
409610923SEvan.Yan@Sun.COM 	DEBUG1("---Vendor ID = [0x%x]\n",
409710923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_VENID));
409810923SEvan.Yan@Sun.COM 	DEBUG1("---Device ID = [0x%x]\n",
409910923SEvan.Yan@Sun.COM 	    pci_config_get16(config_handle, PCI_CONF_DEVID));
410010923SEvan.Yan@Sun.COM 
410110923SEvan.Yan@Sun.COM 	/*
410210923SEvan.Yan@Sun.COM 	 * Attach the child to its parent
410310923SEvan.Yan@Sun.COM 	 */
410410923SEvan.Yan@Sun.COM 	(void) i_ndi_config_node(new_child, DS_LINKED, 0);
410510923SEvan.Yan@Sun.COM 
410610923SEvan.Yan@Sun.COM 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
410710923SEvan.Yan@Sun.COM 
410810923SEvan.Yan@Sun.COM 		DEBUG3("--Bridge found bus [0x%x] device"
410910923SEvan.Yan@Sun.COM 		    "[0x%x] func [0x%x]\n", bus, device, func);
411010923SEvan.Yan@Sun.COM 
411110923SEvan.Yan@Sun.COM 		/* Only support read-only probe for leaf device */
411210923SEvan.Yan@Sun.COM 		if (flags & PCICFG_FLAG_READ_ONLY)
411310923SEvan.Yan@Sun.COM 			goto failedchild;
411410923SEvan.Yan@Sun.COM 
411510923SEvan.Yan@Sun.COM 		if (pcicfg_probe_bridge(new_child, config_handle,
411611245SZhijun.Fu@Sun.COM 		    bus, highest_bus, is_pcie) != PCICFG_SUCCESS) {
411710923SEvan.Yan@Sun.COM 			(void) pcicfg_free_bridge_resources(new_child);
411810923SEvan.Yan@Sun.COM 			goto failedchild;
411910923SEvan.Yan@Sun.COM 		}
412010923SEvan.Yan@Sun.COM 
412110923SEvan.Yan@Sun.COM 	} else {
412210923SEvan.Yan@Sun.COM 
412310923SEvan.Yan@Sun.COM 		DEBUG3("--Leaf device found bus [0x%x] device"
412410923SEvan.Yan@Sun.COM 		    "[0x%x] func [0x%x]\n",
412510923SEvan.Yan@Sun.COM 		    bus, device, func);
412610923SEvan.Yan@Sun.COM 
412710923SEvan.Yan@Sun.COM 		if (flags & PCICFG_FLAG_READ_ONLY) {
412810923SEvan.Yan@Sun.COM 			/*
412910923SEvan.Yan@Sun.COM 			 * with read-only probe, don't do any resource
413010923SEvan.Yan@Sun.COM 			 * allocation, just read the BARs and update props.
413110923SEvan.Yan@Sun.COM 			 */
413210923SEvan.Yan@Sun.COM 			ret = pcicfg_populate_props_from_bar(new_child,
413310923SEvan.Yan@Sun.COM 			    config_handle);
413410923SEvan.Yan@Sun.COM 			if (ret != PCICFG_SUCCESS)
413510923SEvan.Yan@Sun.COM 				goto failedchild;
413610923SEvan.Yan@Sun.COM 
413710923SEvan.Yan@Sun.COM 			/*
413810923SEvan.Yan@Sun.COM 			 * for readonly probe "assigned-addresses" property
413910923SEvan.Yan@Sun.COM 			 * has already been setup by reading the BAR, here
414010923SEvan.Yan@Sun.COM 			 * just substract the resource from its parent here.
414110923SEvan.Yan@Sun.COM 			 */
414210923SEvan.Yan@Sun.COM 			ret = pcicfg_device_assign_readonly(new_child);
414310923SEvan.Yan@Sun.COM 			if (ret != PCICFG_SUCCESS) {
414410923SEvan.Yan@Sun.COM 				(void) pcicfg_free_device_resources(new_child,
414510923SEvan.Yan@Sun.COM 				    flags);
414610923SEvan.Yan@Sun.COM 				goto failedchild;
414710923SEvan.Yan@Sun.COM 			}
414810923SEvan.Yan@Sun.COM 		} else {
414910923SEvan.Yan@Sun.COM 			/*
415010923SEvan.Yan@Sun.COM 			 * update "reg" property by sizing the BARs.
415110923SEvan.Yan@Sun.COM 			 */
415210923SEvan.Yan@Sun.COM 			ret = pcicfg_populate_reg_props(new_child,
415310923SEvan.Yan@Sun.COM 			    config_handle);
415410923SEvan.Yan@Sun.COM 			if (ret != PCICFG_SUCCESS)
415510923SEvan.Yan@Sun.COM 				goto failedchild;
415610923SEvan.Yan@Sun.COM 
415710923SEvan.Yan@Sun.COM 			/* now allocate & program the resources */
415810923SEvan.Yan@Sun.COM 			ret = pcicfg_device_assign(new_child);
415910923SEvan.Yan@Sun.COM 			if (ret != PCICFG_SUCCESS) {
416010923SEvan.Yan@Sun.COM 				(void) pcicfg_free_device_resources(new_child,
416110923SEvan.Yan@Sun.COM 				    flags);
416210923SEvan.Yan@Sun.COM 				goto failedchild;
416310923SEvan.Yan@Sun.COM 			}
416410923SEvan.Yan@Sun.COM 		}
416510923SEvan.Yan@Sun.COM 
416610923SEvan.Yan@Sun.COM 		(void) ndi_devi_bind_driver(new_child, 0);
416710923SEvan.Yan@Sun.COM 	}
416810923SEvan.Yan@Sun.COM 
416910923SEvan.Yan@Sun.COM 	(void) pcicfg_config_teardown(&config_handle);
417011245SZhijun.Fu@Sun.COM 
417111245SZhijun.Fu@Sun.COM 	/*
417211245SZhijun.Fu@Sun.COM 	 * Properties have been setted up, so initilize the rest fields
417311245SZhijun.Fu@Sun.COM 	 * in bus_t.
417411245SZhijun.Fu@Sun.COM 	 */
417511245SZhijun.Fu@Sun.COM 	if (is_pcie)
417611387SSurya.Prakki@Sun.COM 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
417711245SZhijun.Fu@Sun.COM 
417810923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
417910923SEvan.Yan@Sun.COM 
418010923SEvan.Yan@Sun.COM failedchild:
418110923SEvan.Yan@Sun.COM 
418210923SEvan.Yan@Sun.COM 	(void) pcicfg_config_teardown(&config_handle);
418311245SZhijun.Fu@Sun.COM 	if (is_pcie)
418411245SZhijun.Fu@Sun.COM 		pcie_fini_bus(new_child, PCIE_BUS_FINAL);
418510923SEvan.Yan@Sun.COM 
418610923SEvan.Yan@Sun.COM failedconfig:
418710923SEvan.Yan@Sun.COM 
418810923SEvan.Yan@Sun.COM 	(void) ndi_devi_free(new_child);
418910923SEvan.Yan@Sun.COM 	return (PCICFG_FAILURE);
419010923SEvan.Yan@Sun.COM }
419110923SEvan.Yan@Sun.COM 
419210923SEvan.Yan@Sun.COM /*
419310923SEvan.Yan@Sun.COM  * Sizing the BARs and update "reg" property
419410923SEvan.Yan@Sun.COM  */
419510923SEvan.Yan@Sun.COM static int
pcicfg_populate_reg_props(dev_info_t * new_child,ddi_acc_handle_t config_handle)419610923SEvan.Yan@Sun.COM pcicfg_populate_reg_props(dev_info_t *new_child,
419710923SEvan.Yan@Sun.COM     ddi_acc_handle_t config_handle)
419810923SEvan.Yan@Sun.COM {
419910923SEvan.Yan@Sun.COM 	int		i;
420010923SEvan.Yan@Sun.COM 	uint32_t	request;
420110923SEvan.Yan@Sun.COM 
420210923SEvan.Yan@Sun.COM 	i = PCI_CONF_BASE0;
420310923SEvan.Yan@Sun.COM 
420410923SEvan.Yan@Sun.COM 	while (i <= PCI_CONF_BASE5) {
420510923SEvan.Yan@Sun.COM 
420610923SEvan.Yan@Sun.COM 		pci_config_put32(config_handle, i, 0xffffffff);
420710923SEvan.Yan@Sun.COM 
420810923SEvan.Yan@Sun.COM 		request = pci_config_get32(config_handle, i);
420910923SEvan.Yan@Sun.COM 		/*
421010923SEvan.Yan@Sun.COM 		 * If its a zero length, don't do
421110923SEvan.Yan@Sun.COM 		 * any programming.
421210923SEvan.Yan@Sun.COM 		 */
421310923SEvan.Yan@Sun.COM 		if (request != 0) {
421410923SEvan.Yan@Sun.COM 			/*
421510923SEvan.Yan@Sun.COM 			 * Add to the "reg" property
421610923SEvan.Yan@Sun.COM 			 */
421710923SEvan.Yan@Sun.COM 			if (pcicfg_update_reg_prop(new_child,
421810923SEvan.Yan@Sun.COM 			    request, i) != PCICFG_SUCCESS) {
421910923SEvan.Yan@Sun.COM 				goto failedchild;
422010923SEvan.Yan@Sun.COM 			}
422110923SEvan.Yan@Sun.COM 		} else {
422210923SEvan.Yan@Sun.COM 			DEBUG1("BASE register [0x%x] asks for "
422310923SEvan.Yan@Sun.COM 			    "[0x0]=[0x0](32)\n", i);
422410923SEvan.Yan@Sun.COM 			i += 4;
422510923SEvan.Yan@Sun.COM 			continue;
422610923SEvan.Yan@Sun.COM 		}
422710923SEvan.Yan@Sun.COM 
422810923SEvan.Yan@Sun.COM 		/*
422910923SEvan.Yan@Sun.COM 		 * Increment by eight if it is 64 bit address space
423010923SEvan.Yan@Sun.COM 		 */
423110923SEvan.Yan@Sun.COM 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
423210923SEvan.Yan@Sun.COM 			DEBUG3("BASE register [0x%x] asks for "
423310923SEvan.Yan@Sun.COM 			    "[0x%x]=[0x%x] (64)\n",
423410923SEvan.Yan@Sun.COM 			    i, request,
423510923SEvan.Yan@Sun.COM 			    (~(PCI_BASE_M_ADDR_M & request))+1)
423610923SEvan.Yan@Sun.COM 			i += 8;
423710923SEvan.Yan@Sun.COM 		} else {
423810923SEvan.Yan@Sun.COM 			DEBUG3("BASE register [0x%x] asks for "
423910923SEvan.Yan@Sun.COM 			    "[0x%x]=[0x%x](32)\n",
424010923SEvan.Yan@Sun.COM 			    i, request,
424110923SEvan.Yan@Sun.COM 			    (~(PCI_BASE_M_ADDR_M & request))+1)
424210923SEvan.Yan@Sun.COM 			i += 4;
424310923SEvan.Yan@Sun.COM 		}
424410923SEvan.Yan@Sun.COM 	}
424510923SEvan.Yan@Sun.COM 
424610923SEvan.Yan@Sun.COM 	/*
424710923SEvan.Yan@Sun.COM 	 * Get the ROM size and create register for it
424810923SEvan.Yan@Sun.COM 	 */
424910923SEvan.Yan@Sun.COM 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
425010923SEvan.Yan@Sun.COM 
425110923SEvan.Yan@Sun.COM 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
425210923SEvan.Yan@Sun.COM 	/*
425310923SEvan.Yan@Sun.COM 	 * If its a zero length, don't do
425410923SEvan.Yan@Sun.COM 	 * any programming.
425510923SEvan.Yan@Sun.COM 	 */
425610923SEvan.Yan@Sun.COM 
425710923SEvan.Yan@Sun.COM 	if (request != 0) {
425810923SEvan.Yan@Sun.COM 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
425910923SEvan.Yan@Sun.COM 		    PCI_CONF_ROM, request,
426010923SEvan.Yan@Sun.COM 		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
426110923SEvan.Yan@Sun.COM 		/*
426210923SEvan.Yan@Sun.COM 		 * Add to the "reg" property
426310923SEvan.Yan@Sun.COM 		 */
426410923SEvan.Yan@Sun.COM 		if (pcicfg_update_reg_prop(new_child,
426510923SEvan.Yan@Sun.COM 		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
426610923SEvan.Yan@Sun.COM 			goto failedchild;
426710923SEvan.Yan@Sun.COM 		}
426810923SEvan.Yan@Sun.COM 	}
426910923SEvan.Yan@Sun.COM 
427010923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
427110923SEvan.Yan@Sun.COM 
427210923SEvan.Yan@Sun.COM failedchild:
427310923SEvan.Yan@Sun.COM 	return (PCICFG_FAILURE);
427410923SEvan.Yan@Sun.COM }
427510923SEvan.Yan@Sun.COM 
427610923SEvan.Yan@Sun.COM static int
pcicfg_fcode_probe(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)427710923SEvan.Yan@Sun.COM pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
427811245SZhijun.Fu@Sun.COM     uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
427910923SEvan.Yan@Sun.COM {
428010923SEvan.Yan@Sun.COM 	dev_info_t		*new_child;
428110923SEvan.Yan@Sun.COM 	int8_t			header_type;
428210923SEvan.Yan@Sun.COM 	int			ret;
428310923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	h, ph;
428410923SEvan.Yan@Sun.COM 	int			error = 0;
428510923SEvan.Yan@Sun.COM 	extern int		pcicfg_dont_interpret;
428610923SEvan.Yan@Sun.COM 	pcicfg_err_regs_t	parent_regs, regs;
428710923SEvan.Yan@Sun.COM 	char			*status_prop = NULL;
428810923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
428910923SEvan.Yan@Sun.COM 	struct pci_ops_bus_args	po;
429010923SEvan.Yan@Sun.COM 	fco_handle_t		c;
429110923SEvan.Yan@Sun.COM 	char			unit_address[64];
429210923SEvan.Yan@Sun.COM 	int			fcode_size = 0;
429310923SEvan.Yan@Sun.COM 	uchar_t			*fcode_addr;
429410923SEvan.Yan@Sun.COM 	uint64_t		mem_answer, mem_alen;
429510923SEvan.Yan@Sun.COM 	pci_regspec_t		p;
429610923SEvan.Yan@Sun.COM 	int32_t			request;
429710923SEvan.Yan@Sun.COM 	ndi_ra_request_t	req;
429810923SEvan.Yan@Sun.COM 	int16_t			vendor_id, device_id;
429910923SEvan.Yan@Sun.COM #endif
430010923SEvan.Yan@Sun.COM 
430110923SEvan.Yan@Sun.COM 	/*
430210923SEvan.Yan@Sun.COM 	 * check if our parent is of type pciex.
430310923SEvan.Yan@Sun.COM 	 * if so, program config space to disable error msgs during probe.
430410923SEvan.Yan@Sun.COM 	 */
430510923SEvan.Yan@Sun.COM 	if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs)
430610923SEvan.Yan@Sun.COM 	    == DDI_SUCCESS) {
430710923SEvan.Yan@Sun.COM 		DEBUG0("PCI/PCIe parent detected. Disable errors.\n");
430810923SEvan.Yan@Sun.COM 		/*
430910923SEvan.Yan@Sun.COM 		 * disable parent generating URs or SERR#s during probing
431010923SEvan.Yan@Sun.COM 		 * alone.
431110923SEvan.Yan@Sun.COM 		 */
431210923SEvan.Yan@Sun.COM 		if (pci_config_setup(parent, &ph) != DDI_SUCCESS)
431310923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
431410923SEvan.Yan@Sun.COM 
431510923SEvan.Yan@Sun.COM 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
431610923SEvan.Yan@Sun.COM 			pcicfg_disable_bridge_probe_err(parent,
431710923SEvan.Yan@Sun.COM 			    ph, &parent_regs);
431810923SEvan.Yan@Sun.COM 		}
431910923SEvan.Yan@Sun.COM 	}
432010923SEvan.Yan@Sun.COM 
432110923SEvan.Yan@Sun.COM 	/*
432210923SEvan.Yan@Sun.COM 	 * This node will be put immediately below
432310923SEvan.Yan@Sun.COM 	 * "parent". Allocate a blank device node.  It will either
432410923SEvan.Yan@Sun.COM 	 * be filled in or freed up based on further probing.
432510923SEvan.Yan@Sun.COM 	 */
432610923SEvan.Yan@Sun.COM 
432710923SEvan.Yan@Sun.COM 	if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
432810923SEvan.Yan@Sun.COM 	    (pnode_t)DEVI_SID_NODEID, &new_child)
432910923SEvan.Yan@Sun.COM 	    != NDI_SUCCESS) {
433010923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n");
433110923SEvan.Yan@Sun.COM 		/* return (PCICFG_FAILURE); */
433210923SEvan.Yan@Sun.COM 		ret = PCICFG_FAILURE;
433310923SEvan.Yan@Sun.COM 		goto failed2;
433410923SEvan.Yan@Sun.COM 	}
433510923SEvan.Yan@Sun.COM 
433610923SEvan.Yan@Sun.COM 	/*
433710923SEvan.Yan@Sun.COM 	 * Create a dummy reg property.  This will be replaced with
433810923SEvan.Yan@Sun.COM 	 * a real reg property when fcode completes or if we need to
433910923SEvan.Yan@Sun.COM 	 * produce one by hand.
434010923SEvan.Yan@Sun.COM 	 */
434110923SEvan.Yan@Sun.COM 	if (pcicfg_add_config_reg(new_child, bus,
434210923SEvan.Yan@Sun.COM 	    device, func) != DDI_SUCCESS) {
434310923SEvan.Yan@Sun.COM 		ret = PCICFG_FAILURE;
434410923SEvan.Yan@Sun.COM 		goto failed3;
434510923SEvan.Yan@Sun.COM 	}
434610923SEvan.Yan@Sun.COM #ifdef	EFCODE21554
434710923SEvan.Yan@Sun.COM 	if ((ret = pcicfg_config_setup(new_child, &h))
434810923SEvan.Yan@Sun.COM 	    != PCICFG_SUCCESS) {
434910923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_fcode_probe():"
435010923SEvan.Yan@Sun.COM 		    "Failed to setup config space\n");
435110923SEvan.Yan@Sun.COM 		ret = PCICFG_NODEVICE;
435210923SEvan.Yan@Sun.COM 		goto failed3;
435310923SEvan.Yan@Sun.COM 	}
435410923SEvan.Yan@Sun.COM 
435510923SEvan.Yan@Sun.COM #else
435610923SEvan.Yan@Sun.COM 	p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
435710923SEvan.Yan@Sun.COM 	p.pci_phys_mid = p.pci_phys_low = 0;
435810923SEvan.Yan@Sun.COM 	p.pci_size_hi = p.pci_size_low = 0;
435910923SEvan.Yan@Sun.COM 
436010923SEvan.Yan@Sun.COM 	/*
436110923SEvan.Yan@Sun.COM 	 * Map in configuration space (temporarily)
436210923SEvan.Yan@Sun.COM 	 */
436310923SEvan.Yan@Sun.COM 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
436410923SEvan.Yan@Sun.COM 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
436510923SEvan.Yan@Sun.COM 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
436610923SEvan.Yan@Sun.COM 
436710923SEvan.Yan@Sun.COM 	if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) {
436810923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_fcode_probe():"
436910923SEvan.Yan@Sun.COM 		    "Failed to setup config space\n");
437010923SEvan.Yan@Sun.COM 		ret = PCICFG_NODEVICE;
437110923SEvan.Yan@Sun.COM 		goto failed3;
437210923SEvan.Yan@Sun.COM 	}
437310923SEvan.Yan@Sun.COM 
437410923SEvan.Yan@Sun.COM 	/*
437510923SEvan.Yan@Sun.COM 	 * First use ddi_peek16 so that if there is not a device there,
437610923SEvan.Yan@Sun.COM 	 * a bus error will not cause a panic.
437710923SEvan.Yan@Sun.COM 	 */
437810923SEvan.Yan@Sun.COM 	v = virt + PCI_CONF_VENID;
437910923SEvan.Yan@Sun.COM 	if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) {
438010923SEvan.Yan@Sun.COM 		DEBUG0("Can not read Vendor ID");
438110923SEvan.Yan@Sun.COM 		pcicfg_unmap_phys(&h, &p);
438210923SEvan.Yan@Sun.COM 		ret = PCICFG_NODEVICE;
438310923SEvan.Yan@Sun.COM 		goto failed3;
438410923SEvan.Yan@Sun.COM 	}
438510923SEvan.Yan@Sun.COM #endif
438611245SZhijun.Fu@Sun.COM 
438711245SZhijun.Fu@Sun.COM 	if (is_pcie)
438811245SZhijun.Fu@Sun.COM 		(void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
438911245SZhijun.Fu@Sun.COM 		    PCIE_BUS_INITIAL);
439011245SZhijun.Fu@Sun.COM 
439110923SEvan.Yan@Sun.COM 	DEBUG0("fcode_probe: conf space mapped.\n");
439210923SEvan.Yan@Sun.COM 	/*
439310923SEvan.Yan@Sun.COM 	 * As soon as we have access to config space,
439410923SEvan.Yan@Sun.COM 	 * turn off device. It will get turned on
439510923SEvan.Yan@Sun.COM 	 * later (after memory is assigned).
439610923SEvan.Yan@Sun.COM 	 */
439710923SEvan.Yan@Sun.COM 	(void) pcicfg_device_off(h);
439810923SEvan.Yan@Sun.COM 
439910923SEvan.Yan@Sun.COM 	/* check if we are PCIe device */
440010923SEvan.Yan@Sun.COM 	if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
440110923SEvan.Yan@Sun.COM 	    == DDI_SUCCESS) {
440210923SEvan.Yan@Sun.COM 		/*EMPTY*/
440310923SEvan.Yan@Sun.COM 		DEBUG0("PCI/PCIe device detected\n");
440410923SEvan.Yan@Sun.COM 	}
440510923SEvan.Yan@Sun.COM 
440610923SEvan.Yan@Sun.COM 	/*
440710923SEvan.Yan@Sun.COM 	 * Set 1275 properties common to all devices
440810923SEvan.Yan@Sun.COM 	 */
440910923SEvan.Yan@Sun.COM 	if (pcicfg_set_standard_props(new_child,
441010923SEvan.Yan@Sun.COM 	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
441110923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set standard properties\n");
441210923SEvan.Yan@Sun.COM 		goto failed;
441310923SEvan.Yan@Sun.COM 	}
441410923SEvan.Yan@Sun.COM 
441510923SEvan.Yan@Sun.COM 	/*
441610923SEvan.Yan@Sun.COM 	 * Child node properties  NOTE: Both for PCI-PCI bridge and child node
441710923SEvan.Yan@Sun.COM 	 */
441810923SEvan.Yan@Sun.COM 	if (pcicfg_set_childnode_props(new_child,
441910923SEvan.Yan@Sun.COM 	    h, regs.pcie_dev) != PCICFG_SUCCESS) {
442010923SEvan.Yan@Sun.COM 		ret = PCICFG_FAILURE;
442110923SEvan.Yan@Sun.COM 		goto failed;
442210923SEvan.Yan@Sun.COM 	}
442310923SEvan.Yan@Sun.COM 
442410923SEvan.Yan@Sun.COM 	header_type = pci_config_get8(h, PCI_CONF_HEADER);
442510923SEvan.Yan@Sun.COM 
442610923SEvan.Yan@Sun.COM 	/*
442710923SEvan.Yan@Sun.COM 	 * If this is not a multi-function card only probe function zero.
442810923SEvan.Yan@Sun.COM 	 */
442910923SEvan.Yan@Sun.COM 	if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) {
443010923SEvan.Yan@Sun.COM 
443110923SEvan.Yan@Sun.COM 		ret = PCICFG_NODEVICE;
443210923SEvan.Yan@Sun.COM 		goto failed;
443310923SEvan.Yan@Sun.COM 	}
443410923SEvan.Yan@Sun.COM 
443510923SEvan.Yan@Sun.COM 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
443610923SEvan.Yan@Sun.COM 
443710923SEvan.Yan@Sun.COM 		/*
443810923SEvan.Yan@Sun.COM 		 * XXX - Transparent bridges are handled differently
443910923SEvan.Yan@Sun.COM 		 * than other devices with regards to fcode.  Since
444010923SEvan.Yan@Sun.COM 		 * no transparent bridge currently ships with fcode,
444110923SEvan.Yan@Sun.COM 		 * there is no reason to try to extract it from its rom
444210923SEvan.Yan@Sun.COM 		 * or call the fcode interpreter to try to load a drop-in.
444310923SEvan.Yan@Sun.COM 		 * If fcode is developed to handle transparent bridges,
444410923SEvan.Yan@Sun.COM 		 * this code will have to change.
444510923SEvan.Yan@Sun.COM 		 */
444610923SEvan.Yan@Sun.COM 
444710923SEvan.Yan@Sun.COM 		DEBUG3("--Bridge found bus [0x%x] device"
444810923SEvan.Yan@Sun.COM 		    "[0x%x] func [0x%x]\n", bus, device, func);
444910923SEvan.Yan@Sun.COM 
445010923SEvan.Yan@Sun.COM 		/* Only support read-only probe for leaf device */
445110923SEvan.Yan@Sun.COM 		if (flags & PCICFG_FLAG_READ_ONLY)
445210923SEvan.Yan@Sun.COM 			goto failed;
445310923SEvan.Yan@Sun.COM 
445410923SEvan.Yan@Sun.COM 		if ((ret = pcicfg_probe_bridge(new_child, h,
445511245SZhijun.Fu@Sun.COM 		    bus, highest_bus, is_pcie)) != PCICFG_SUCCESS)
445610923SEvan.Yan@Sun.COM 			(void) pcicfg_free_bridge_resources(new_child);
445710923SEvan.Yan@Sun.COM 		goto done;
445810923SEvan.Yan@Sun.COM 	} else {
445910923SEvan.Yan@Sun.COM 
446010923SEvan.Yan@Sun.COM 		DEBUG3("--Leaf device found bus [0x%x] device"
446110923SEvan.Yan@Sun.COM 		    "[0x%x] func [0x%x]\n",
446210923SEvan.Yan@Sun.COM 		    bus, device, func);
446310923SEvan.Yan@Sun.COM 
446410923SEvan.Yan@Sun.COM 		/*
446510923SEvan.Yan@Sun.COM 		 * link in tree, but don't bind driver
446610923SEvan.Yan@Sun.COM 		 * We don't have compatible property yet
446710923SEvan.Yan@Sun.COM 		 */
446810923SEvan.Yan@Sun.COM 		(void) i_ndi_config_node(new_child, DS_LINKED, 0);
446910923SEvan.Yan@Sun.COM 
447010923SEvan.Yan@Sun.COM 		/* XXX for now, don't run Fcode in read-only probe. */
447110923SEvan.Yan@Sun.COM 		if (flags & PCICFG_FLAG_READ_ONLY)
447210923SEvan.Yan@Sun.COM 			goto no_fcode;
447310923SEvan.Yan@Sun.COM 
447410923SEvan.Yan@Sun.COM 		if (pci_config_get8(h, PCI_CONF_IPIN)) {
447510923SEvan.Yan@Sun.COM 			pci_config_put8(h, PCI_CONF_ILINE, 0xf);
447610923SEvan.Yan@Sun.COM 		}
447710923SEvan.Yan@Sun.COM 
447810923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
447910923SEvan.Yan@Sun.COM 		/*
448010923SEvan.Yan@Sun.COM 		 * Some platforms (x86) don't run fcode, so don't interpret
448110923SEvan.Yan@Sun.COM 		 * fcode that might be in the ROM.
448210923SEvan.Yan@Sun.COM 		 */
448310923SEvan.Yan@Sun.COM 		if (pcicfg_dont_interpret == 0) {
448410923SEvan.Yan@Sun.COM 
448510923SEvan.Yan@Sun.COM 			/* This platform supports fcode */
448610923SEvan.Yan@Sun.COM 
448710923SEvan.Yan@Sun.COM 			vendor_id = pci_config_get16(h, PCI_CONF_VENID);
448810923SEvan.Yan@Sun.COM 			device_id = pci_config_get16(h, PCI_CONF_DEVID);
448910923SEvan.Yan@Sun.COM 
449010923SEvan.Yan@Sun.COM 			/*
449110923SEvan.Yan@Sun.COM 			 * Get the ROM size and create register for it
449210923SEvan.Yan@Sun.COM 			 */
449310923SEvan.Yan@Sun.COM 			pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe);
449410923SEvan.Yan@Sun.COM 
449510923SEvan.Yan@Sun.COM 			request = pci_config_get32(h, PCI_CONF_ROM);
449610923SEvan.Yan@Sun.COM 
449710923SEvan.Yan@Sun.COM 			/*
449810923SEvan.Yan@Sun.COM 			 * If its a zero length, don't do
449910923SEvan.Yan@Sun.COM 			 * any programming.
450010923SEvan.Yan@Sun.COM 			 */
450110923SEvan.Yan@Sun.COM 
450210923SEvan.Yan@Sun.COM 			if (request != 0) {
450310923SEvan.Yan@Sun.COM 				/*
450410923SEvan.Yan@Sun.COM 				 * Add resource to assigned-addresses.
450510923SEvan.Yan@Sun.COM 				 */
450610923SEvan.Yan@Sun.COM 				if (pcicfg_fcode_assign_bars(h, new_child,
450710923SEvan.Yan@Sun.COM 				    bus, device, func, request, &p)
450810923SEvan.Yan@Sun.COM 				    != PCICFG_SUCCESS) {
450910923SEvan.Yan@Sun.COM 					DEBUG0("Failed to assign addresses to "
451010923SEvan.Yan@Sun.COM 					    "implemented BARs");
451110923SEvan.Yan@Sun.COM 					ret = PCICFG_FAILURE;
451210923SEvan.Yan@Sun.COM 					goto failed;
451310923SEvan.Yan@Sun.COM 				}
451410923SEvan.Yan@Sun.COM 
451510923SEvan.Yan@Sun.COM 				/* Turn device on */
451610923SEvan.Yan@Sun.COM 				(void) pcicfg_device_on(h);
451710923SEvan.Yan@Sun.COM 
451810923SEvan.Yan@Sun.COM 				/*
451910923SEvan.Yan@Sun.COM 				 * Attempt to load fcode.
452010923SEvan.Yan@Sun.COM 				 */
452110923SEvan.Yan@Sun.COM 				(void) pcicfg_load_fcode(new_child, bus, device,
452210923SEvan.Yan@Sun.COM 				    func, vendor_id, device_id, &fcode_addr,
452310923SEvan.Yan@Sun.COM 				    &fcode_size, PCICFG_LOADDR(mem_answer),
452410923SEvan.Yan@Sun.COM 				    (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
452510923SEvan.Yan@Sun.COM 
452610923SEvan.Yan@Sun.COM 				/* Turn device off */
452710923SEvan.Yan@Sun.COM 				(void) pcicfg_device_off(h);
452810923SEvan.Yan@Sun.COM 
452910923SEvan.Yan@Sun.COM 				/*
453010923SEvan.Yan@Sun.COM 				 * Free the ROM resources.
453110923SEvan.Yan@Sun.COM 				 */
453210923SEvan.Yan@Sun.COM 				(void) pcicfg_free_resource(new_child, p, 0);
453310923SEvan.Yan@Sun.COM 
453410923SEvan.Yan@Sun.COM 				DEBUG2("configure: fcode addr %lx size %x\n",
453510923SEvan.Yan@Sun.COM 				    fcode_addr, fcode_size);
453610923SEvan.Yan@Sun.COM 
453710923SEvan.Yan@Sun.COM 				/*
453810923SEvan.Yan@Sun.COM 				 * Create the fcode-rom-offset property.  The
453910923SEvan.Yan@Sun.COM 				 * buffer containing the fcode always starts
454010923SEvan.Yan@Sun.COM 				 * with 0xF1, so the fcode offset is zero.
454110923SEvan.Yan@Sun.COM 				 */
454210923SEvan.Yan@Sun.COM 				if (ndi_prop_update_int(DDI_DEV_T_NONE,
454310923SEvan.Yan@Sun.COM 				    new_child, "fcode-rom-offset", 0)
454410923SEvan.Yan@Sun.COM 				    != DDI_SUCCESS) {
454510923SEvan.Yan@Sun.COM 					DEBUG0("Failed to create "
454610923SEvan.Yan@Sun.COM 					    "fcode-rom-offset property\n");
454710923SEvan.Yan@Sun.COM 					ret = PCICFG_FAILURE;
454810923SEvan.Yan@Sun.COM 					goto failed;
454910923SEvan.Yan@Sun.COM 				}
455010923SEvan.Yan@Sun.COM 			} else {
455110923SEvan.Yan@Sun.COM 				DEBUG0("There is no Expansion ROM\n");
455210923SEvan.Yan@Sun.COM 				fcode_addr = NULL;
455310923SEvan.Yan@Sun.COM 				fcode_size = 0;
455410923SEvan.Yan@Sun.COM 			}
455510923SEvan.Yan@Sun.COM 
455610923SEvan.Yan@Sun.COM 			/*
455710923SEvan.Yan@Sun.COM 			 * Fill in the bus specific arguments. For
455810923SEvan.Yan@Sun.COM 			 * PCI, it is the config address.
455910923SEvan.Yan@Sun.COM 			 */
456010923SEvan.Yan@Sun.COM 			po.config_address =
456110923SEvan.Yan@Sun.COM 			    PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
456210923SEvan.Yan@Sun.COM 
456310923SEvan.Yan@Sun.COM 			DEBUG1("config_address=%x\n", po.config_address);
456410923SEvan.Yan@Sun.COM 
456510923SEvan.Yan@Sun.COM 			/*
456610923SEvan.Yan@Sun.COM 			 * Build unit address.
456710923SEvan.Yan@Sun.COM 			 */
456810923SEvan.Yan@Sun.COM 			(void) sprintf(unit_address, "%x,%x", device, func);
456910923SEvan.Yan@Sun.COM 
457010923SEvan.Yan@Sun.COM 			DEBUG3("pci_fc_ops_alloc_handle ap=%lx "
457110923SEvan.Yan@Sun.COM 			    "new device=%lx unit address=%s\n",
457210923SEvan.Yan@Sun.COM 			    parent, new_child, unit_address);
457310923SEvan.Yan@Sun.COM 
457410923SEvan.Yan@Sun.COM 			c = pci_fc_ops_alloc_handle(parent, new_child,
457510923SEvan.Yan@Sun.COM 			    fcode_addr, fcode_size, unit_address, &po);
457610923SEvan.Yan@Sun.COM 
457710923SEvan.Yan@Sun.COM 			DEBUG0("calling fcode_interpreter()\n");
457810923SEvan.Yan@Sun.COM 
457910923SEvan.Yan@Sun.COM 			DEBUG3("Before int DIP=%lx binding name %s major %d\n",
458010923SEvan.Yan@Sun.COM 			    new_child, ddi_binding_name(new_child),
458110923SEvan.Yan@Sun.COM 			    ddi_driver_major(new_child));
458210923SEvan.Yan@Sun.COM 
458310923SEvan.Yan@Sun.COM 			error = fcode_interpreter(parent, &pci_fc_ops, c);
458410923SEvan.Yan@Sun.COM 
458510923SEvan.Yan@Sun.COM 			DEBUG1("returned from fcode_interpreter() - "
458610923SEvan.Yan@Sun.COM 			    "returned %x\n", error);
458710923SEvan.Yan@Sun.COM 
458810923SEvan.Yan@Sun.COM 			pci_fc_ops_free_handle(c);
458910923SEvan.Yan@Sun.COM 
459010923SEvan.Yan@Sun.COM 			DEBUG1("fcode size = %x\n", fcode_size);
459110923SEvan.Yan@Sun.COM 			/*
459210923SEvan.Yan@Sun.COM 			 * We don't need the fcode anymore. While allocating
459310923SEvan.Yan@Sun.COM 			 * we had rounded up to a page size.
459410923SEvan.Yan@Sun.COM 			 */
459510923SEvan.Yan@Sun.COM 			if (fcode_size) {
459610923SEvan.Yan@Sun.COM 				kmem_free(fcode_addr, ptob(btopr(fcode_size)));
459710923SEvan.Yan@Sun.COM 			}
459810923SEvan.Yan@Sun.COM 		} else {
459910923SEvan.Yan@Sun.COM 			/* This platform does not support fcode */
460010923SEvan.Yan@Sun.COM 
460110923SEvan.Yan@Sun.COM 			DEBUG0("NOT calling fcode_interpreter()\n");
460210923SEvan.Yan@Sun.COM 		}
460310923SEvan.Yan@Sun.COM 
460410923SEvan.Yan@Sun.COM #endif /* PCICFG_INTERPRET_FCODE */
460510923SEvan.Yan@Sun.COM 
460610923SEvan.Yan@Sun.COM 		if ((error == 0) && (pcicfg_dont_interpret == 0)) {
460710923SEvan.Yan@Sun.COM 			/*
460810923SEvan.Yan@Sun.COM 			 * The interpreter completed successfully.
460910923SEvan.Yan@Sun.COM 			 * We need to redo the resources based on the new reg
461010923SEvan.Yan@Sun.COM 			 * property.
461110923SEvan.Yan@Sun.COM 			 */
461210923SEvan.Yan@Sun.COM 			DEBUG3("DIP=%lx binding name %s major %d\n", new_child,
461310923SEvan.Yan@Sun.COM 			    ddi_binding_name(new_child),
461410923SEvan.Yan@Sun.COM 			    ddi_driver_major(new_child));
461510923SEvan.Yan@Sun.COM 
461610923SEvan.Yan@Sun.COM 			/*
461710923SEvan.Yan@Sun.COM 			 * Readjust resources specified by reg property.
461810923SEvan.Yan@Sun.COM 			 */
461910923SEvan.Yan@Sun.COM 			if (pcicfg_alloc_new_resources(new_child) ==
462010923SEvan.Yan@Sun.COM 			    PCICFG_FAILURE) {
462110923SEvan.Yan@Sun.COM 				ret = PCICFG_FAILURE;
462210923SEvan.Yan@Sun.COM 				goto failed;
462310923SEvan.Yan@Sun.COM 			}
462410923SEvan.Yan@Sun.COM 
462510923SEvan.Yan@Sun.COM 			/*
462610923SEvan.Yan@Sun.COM 			 * At this stage, there should be enough info to pull
462710923SEvan.Yan@Sun.COM 			 * the status property if it exists.
462810923SEvan.Yan@Sun.COM 			 */
462910923SEvan.Yan@Sun.COM 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY,
463010923SEvan.Yan@Sun.COM 			    new_child, NULL, "status", &status_prop) ==
463110923SEvan.Yan@Sun.COM 			    DDI_PROP_SUCCESS) {
463210923SEvan.Yan@Sun.COM 				if ((strncmp("disabled", status_prop, 8) ==
463310923SEvan.Yan@Sun.COM 				    0) || (strncmp("fail", status_prop, 4) ==
463410923SEvan.Yan@Sun.COM 				    0)) {
463510923SEvan.Yan@Sun.COM 					ret = PCICFG_FAILURE;
463610923SEvan.Yan@Sun.COM 					ddi_prop_free(status_prop);
463710923SEvan.Yan@Sun.COM 					goto failed;
463810923SEvan.Yan@Sun.COM 				} else {
463910923SEvan.Yan@Sun.COM 					ddi_prop_free(status_prop);
464010923SEvan.Yan@Sun.COM 				}
464110923SEvan.Yan@Sun.COM 			}
464210923SEvan.Yan@Sun.COM 
464310923SEvan.Yan@Sun.COM 			ret = PCICFG_SUCCESS;
464410923SEvan.Yan@Sun.COM 			/* no fcode, bind driver now */
464510923SEvan.Yan@Sun.COM 			(void) ndi_devi_bind_driver(new_child, 0);
464610923SEvan.Yan@Sun.COM 
464710923SEvan.Yan@Sun.COM 			goto done;
464810923SEvan.Yan@Sun.COM 		} else if ((error != FC_NO_FCODE) &&
464910923SEvan.Yan@Sun.COM 		    (pcicfg_dont_interpret == 0))  {
465010923SEvan.Yan@Sun.COM 			/*
465110923SEvan.Yan@Sun.COM 			 * The interpreter located fcode, but had an error in
465210923SEvan.Yan@Sun.COM 			 * processing. Cleanup and fail the operation.
465310923SEvan.Yan@Sun.COM 			 */
465410923SEvan.Yan@Sun.COM 			DEBUG0("Interpreter detected fcode failure\n");
465510923SEvan.Yan@Sun.COM 			(void) pcicfg_free_resources(new_child, flags);
465610923SEvan.Yan@Sun.COM 			ret = PCICFG_FAILURE;
465710923SEvan.Yan@Sun.COM 			goto failed;
465810923SEvan.Yan@Sun.COM 		} else {
465910923SEvan.Yan@Sun.COM no_fcode:
466010923SEvan.Yan@Sun.COM 			/*
466110923SEvan.Yan@Sun.COM 			 * Either the interpreter failed with FC_NO_FCODE or we
466210923SEvan.Yan@Sun.COM 			 * chose not to run the interpreter
466310923SEvan.Yan@Sun.COM 			 * (pcicfg_dont_interpret).
466410923SEvan.Yan@Sun.COM 			 *
466510923SEvan.Yan@Sun.COM 			 * If the interpreter failed because there was no
466610923SEvan.Yan@Sun.COM 			 * dropin, then we need to probe the device ourself.
466710923SEvan.Yan@Sun.COM 			 */
466810923SEvan.Yan@Sun.COM 
466910923SEvan.Yan@Sun.COM 			/*
467010923SEvan.Yan@Sun.COM 			 * Free any resources that may have been assigned
467110923SEvan.Yan@Sun.COM 			 * during fcode loading/execution since we need
467210923SEvan.Yan@Sun.COM 			 * to start over.
467310923SEvan.Yan@Sun.COM 			 */
467410923SEvan.Yan@Sun.COM 			(void) pcicfg_free_resources(new_child, flags);
467510923SEvan.Yan@Sun.COM 
467610923SEvan.Yan@Sun.COM #ifdef	EFCODE21554
467710923SEvan.Yan@Sun.COM 			pcicfg_config_teardown(&h);
467810923SEvan.Yan@Sun.COM #else
467910923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &p);
468010923SEvan.Yan@Sun.COM #endif
468111245SZhijun.Fu@Sun.COM 			/* destroy the bus_t before the dev node is gone */
468211245SZhijun.Fu@Sun.COM 			if (is_pcie)
468311245SZhijun.Fu@Sun.COM 				pcie_fini_bus(new_child, PCIE_BUS_FINAL);
468411245SZhijun.Fu@Sun.COM 
468510923SEvan.Yan@Sun.COM 			(void) ndi_devi_free(new_child);
468610923SEvan.Yan@Sun.COM 
468710923SEvan.Yan@Sun.COM 			DEBUG0("No Drop-in Probe device ourself\n");
468810923SEvan.Yan@Sun.COM 
468910923SEvan.Yan@Sun.COM 			ret = pcicfg_probe_children(parent, bus, device, func,
469011245SZhijun.Fu@Sun.COM 			    highest_bus, flags, is_pcie);
469110923SEvan.Yan@Sun.COM 
469210923SEvan.Yan@Sun.COM 			if (ret != PCICFG_SUCCESS) {
469310923SEvan.Yan@Sun.COM 				DEBUG0("Could not self probe child\n");
469410923SEvan.Yan@Sun.COM 				goto failed2;
469510923SEvan.Yan@Sun.COM 			}
469610923SEvan.Yan@Sun.COM 
469710923SEvan.Yan@Sun.COM 			/*
469810923SEvan.Yan@Sun.COM 			 * We successfully self probed the device.
469910923SEvan.Yan@Sun.COM 			 */
470010923SEvan.Yan@Sun.COM 			if ((new_child = pcicfg_devi_find(
470110923SEvan.Yan@Sun.COM 			    parent, device, func)) == NULL) {
470210923SEvan.Yan@Sun.COM 				DEBUG0("Did'nt find device node "
470310923SEvan.Yan@Sun.COM 				    "just created\n");
470410923SEvan.Yan@Sun.COM 				ret = PCICFG_FAILURE;
470510923SEvan.Yan@Sun.COM 				goto failed2;
470610923SEvan.Yan@Sun.COM 			}
470710923SEvan.Yan@Sun.COM #ifdef	EFCODE21554
470810923SEvan.Yan@Sun.COM 			/*
470910923SEvan.Yan@Sun.COM 			 * Till now, we have detected a non transparent bridge
471010923SEvan.Yan@Sun.COM 			 * (ntbridge) as a part of the generic probe code and
471110923SEvan.Yan@Sun.COM 			 * configured only one configuration
471210923SEvan.Yan@Sun.COM 			 * header which is the side facing the host bus.
471310923SEvan.Yan@Sun.COM 			 * Now, configure the other side and create children.
471410923SEvan.Yan@Sun.COM 			 *
471510923SEvan.Yan@Sun.COM 			 * To make the process simpler, lets load the device
471610923SEvan.Yan@Sun.COM 			 * driver for the non transparent bridge as this is a
471710923SEvan.Yan@Sun.COM 			 * Solaris bundled driver, and use its configuration map
471810923SEvan.Yan@Sun.COM 			 * services rather than programming it here.
471910923SEvan.Yan@Sun.COM 			 * If the driver is not bundled into Solaris, it must be
472010923SEvan.Yan@Sun.COM 			 * first loaded and configured before performing any
472110923SEvan.Yan@Sun.COM 			 * hotplug operations.
472210923SEvan.Yan@Sun.COM 			 *
472310923SEvan.Yan@Sun.COM 			 * This not only makes the code simpler but also more
472410923SEvan.Yan@Sun.COM 			 * generic.
472510923SEvan.Yan@Sun.COM 			 *
472610923SEvan.Yan@Sun.COM 			 * So here we go.
472710923SEvan.Yan@Sun.COM 			 */
472810923SEvan.Yan@Sun.COM 			if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) {
472910923SEvan.Yan@Sun.COM 
473010923SEvan.Yan@Sun.COM 				DEBUG0("Found nontransparent bridge.\n");
473110923SEvan.Yan@Sun.COM 
473210923SEvan.Yan@Sun.COM 				ret = pcicfg_configure_ntbridge(new_child,
473310923SEvan.Yan@Sun.COM 				    bus, device);
473410923SEvan.Yan@Sun.COM 			}
473510923SEvan.Yan@Sun.COM 			if (ret != PCICFG_SUCCESS) {
473610923SEvan.Yan@Sun.COM 				/*
473710923SEvan.Yan@Sun.COM 				 * Bridge configure failed. Free up the self
473810923SEvan.Yan@Sun.COM 				 * probed entry. The bus resource allocation
473910923SEvan.Yan@Sun.COM 				 * maps need to be cleaned up to prevent
474010923SEvan.Yan@Sun.COM 				 * warnings on retries of the failed configure.
474110923SEvan.Yan@Sun.COM 				 */
474210923SEvan.Yan@Sun.COM 				(void) pcicfg_ntbridge_unconfigure(new_child);
474311245SZhijun.Fu@Sun.COM 				(void) pcicfg_teardown_device(new_child,
474411245SZhijun.Fu@Sun.COM 				    flags, is_pcie);
474510923SEvan.Yan@Sun.COM 			}
474610923SEvan.Yan@Sun.COM #endif
474710923SEvan.Yan@Sun.COM 			goto done2;
474810923SEvan.Yan@Sun.COM 		}
474910923SEvan.Yan@Sun.COM 	}
475010923SEvan.Yan@Sun.COM done:
475110923SEvan.Yan@Sun.COM failed:
475211245SZhijun.Fu@Sun.COM 	if (is_pcie) {
475311245SZhijun.Fu@Sun.COM 		if (ret == PCICFG_SUCCESS)
475411387SSurya.Prakki@Sun.COM 			(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
475511245SZhijun.Fu@Sun.COM 		else
475611245SZhijun.Fu@Sun.COM 			pcie_fini_bus(new_child, PCIE_BUS_FINAL);
475711245SZhijun.Fu@Sun.COM 	}
475811245SZhijun.Fu@Sun.COM 
475910923SEvan.Yan@Sun.COM #ifdef	EFCODE21554
476010923SEvan.Yan@Sun.COM 	pcicfg_config_teardown(&h);
476110923SEvan.Yan@Sun.COM #else
476210923SEvan.Yan@Sun.COM 	pcicfg_unmap_phys(&h, &p);
476310923SEvan.Yan@Sun.COM #endif
476410923SEvan.Yan@Sun.COM failed3:
476510923SEvan.Yan@Sun.COM 	if (ret != PCICFG_SUCCESS)
476610923SEvan.Yan@Sun.COM 		(void) ndi_devi_free(new_child);
476710923SEvan.Yan@Sun.COM done2:
476810923SEvan.Yan@Sun.COM failed2:
476910923SEvan.Yan@Sun.COM 	if (parent_regs.pcie_dev) {
477010923SEvan.Yan@Sun.COM 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
477110923SEvan.Yan@Sun.COM 			pcicfg_enable_bridge_probe_err(parent,
477210923SEvan.Yan@Sun.COM 			    ph, &parent_regs);
477310923SEvan.Yan@Sun.COM 		}
477410923SEvan.Yan@Sun.COM 		pci_config_teardown(&ph);
477510923SEvan.Yan@Sun.COM 	}
477611245SZhijun.Fu@Sun.COM 
477710923SEvan.Yan@Sun.COM 	return (ret);
477810923SEvan.Yan@Sun.COM }
477910923SEvan.Yan@Sun.COM 
478010923SEvan.Yan@Sun.COM /*
478110923SEvan.Yan@Sun.COM  * Read the BARs and update properties. Used in virtual hotplug.
478210923SEvan.Yan@Sun.COM  */
478310923SEvan.Yan@Sun.COM static int
pcicfg_populate_props_from_bar(dev_info_t * new_child,ddi_acc_handle_t config_handle)478410923SEvan.Yan@Sun.COM pcicfg_populate_props_from_bar(dev_info_t *new_child,
478510923SEvan.Yan@Sun.COM     ddi_acc_handle_t config_handle)
478610923SEvan.Yan@Sun.COM {
478710923SEvan.Yan@Sun.COM 	uint32_t request, base, base_hi, size;
478810923SEvan.Yan@Sun.COM 	int i;
478910923SEvan.Yan@Sun.COM 
479010923SEvan.Yan@Sun.COM 	i = PCI_CONF_BASE0;
479110923SEvan.Yan@Sun.COM 
479210923SEvan.Yan@Sun.COM 	while (i <= PCI_CONF_BASE5) {
479310923SEvan.Yan@Sun.COM 		/*
479410923SEvan.Yan@Sun.COM 		 * determine the size of the address space
479510923SEvan.Yan@Sun.COM 		 */
479610923SEvan.Yan@Sun.COM 		base = pci_config_get32(config_handle, i);
479710923SEvan.Yan@Sun.COM 		pci_config_put32(config_handle, i, 0xffffffff);
479810923SEvan.Yan@Sun.COM 		request = pci_config_get32(config_handle, i);
479910923SEvan.Yan@Sun.COM 		pci_config_put32(config_handle, i, base);
480010923SEvan.Yan@Sun.COM 
480110923SEvan.Yan@Sun.COM 		/*
480210923SEvan.Yan@Sun.COM 		 * If its a zero length, don't do any programming.
480310923SEvan.Yan@Sun.COM 		 */
480410923SEvan.Yan@Sun.COM 		if (request != 0) {
480510923SEvan.Yan@Sun.COM 			/*
480610923SEvan.Yan@Sun.COM 			 * Add to the "reg" property
480710923SEvan.Yan@Sun.COM 			 */
480810923SEvan.Yan@Sun.COM 			if (pcicfg_update_reg_prop(new_child,
480910923SEvan.Yan@Sun.COM 			    request, i) != PCICFG_SUCCESS) {
481010923SEvan.Yan@Sun.COM 				goto failedchild;
481110923SEvan.Yan@Sun.COM 			}
481210923SEvan.Yan@Sun.COM 
481310923SEvan.Yan@Sun.COM 			if ((PCI_BASE_SPACE_IO & request) == 0 &&
481410923SEvan.Yan@Sun.COM 			    (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
481510923SEvan.Yan@Sun.COM 				base_hi = pci_config_get32(config_handle, i+4);
481610923SEvan.Yan@Sun.COM 			} else {
481710923SEvan.Yan@Sun.COM 				base_hi = 0;
481810923SEvan.Yan@Sun.COM 			}
481910923SEvan.Yan@Sun.COM 			/*
482010923SEvan.Yan@Sun.COM 			 * Add to "assigned-addresses" property
482110923SEvan.Yan@Sun.COM 			 */
482210923SEvan.Yan@Sun.COM 			size = (~(PCI_BASE_M_ADDR_M & request))+1;
482310923SEvan.Yan@Sun.COM 			if (pcicfg_update_assigned_prop_value(new_child,
482410923SEvan.Yan@Sun.COM 			    size, base, base_hi, i) != PCICFG_SUCCESS) {
482510923SEvan.Yan@Sun.COM 				goto failedchild;
482610923SEvan.Yan@Sun.COM 			}
482710923SEvan.Yan@Sun.COM 		} else {
482810923SEvan.Yan@Sun.COM 			DEBUG1("BASE register [0x%x] asks for "
482910923SEvan.Yan@Sun.COM 			"[0x0]=[0x0](32)\n", i);
483010923SEvan.Yan@Sun.COM 			i += 4;
483110923SEvan.Yan@Sun.COM 			continue;
483210923SEvan.Yan@Sun.COM 		}
483310923SEvan.Yan@Sun.COM 
483410923SEvan.Yan@Sun.COM 		/*
483510923SEvan.Yan@Sun.COM 		 * Increment by eight if it is 64 bit address space
483610923SEvan.Yan@Sun.COM 		 */
483710923SEvan.Yan@Sun.COM 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
483810923SEvan.Yan@Sun.COM 			DEBUG3("BASE register [0x%x] asks for "
483910923SEvan.Yan@Sun.COM 			"[0x%x]=[0x%x] (64)\n",
484010923SEvan.Yan@Sun.COM 			    i, request,
484110923SEvan.Yan@Sun.COM 			    (~(PCI_BASE_M_ADDR_M & request))+1)
484210923SEvan.Yan@Sun.COM 			i += 8;
484310923SEvan.Yan@Sun.COM 		} else {
484410923SEvan.Yan@Sun.COM 			DEBUG3("BASE register [0x%x] asks for "
484510923SEvan.Yan@Sun.COM 			"[0x%x]=[0x%x](32)\n",
484610923SEvan.Yan@Sun.COM 			    i, request,
484710923SEvan.Yan@Sun.COM 			    (~(PCI_BASE_M_ADDR_M & request))+1)
484810923SEvan.Yan@Sun.COM 			i += 4;
484910923SEvan.Yan@Sun.COM 		}
485010923SEvan.Yan@Sun.COM 	}
485110923SEvan.Yan@Sun.COM 
485210923SEvan.Yan@Sun.COM 	/*
485310923SEvan.Yan@Sun.COM 	 * Get the ROM size and create register for it
485410923SEvan.Yan@Sun.COM 	 */
485510923SEvan.Yan@Sun.COM 	base = pci_config_get32(config_handle, PCI_CONF_ROM);
485610923SEvan.Yan@Sun.COM 	pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
485710923SEvan.Yan@Sun.COM 	request = pci_config_get32(config_handle, PCI_CONF_ROM);
485810923SEvan.Yan@Sun.COM 	pci_config_put32(config_handle, PCI_CONF_ROM, base);
485910923SEvan.Yan@Sun.COM 
486010923SEvan.Yan@Sun.COM 	/*
486110923SEvan.Yan@Sun.COM 	 * If its a zero length, don't do
486210923SEvan.Yan@Sun.COM 	 * any programming.
486310923SEvan.Yan@Sun.COM 	 */
486410923SEvan.Yan@Sun.COM 	if (request != 0) {
486510923SEvan.Yan@Sun.COM 		DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
486610923SEvan.Yan@Sun.COM 		    PCI_CONF_ROM, request,
486710923SEvan.Yan@Sun.COM 		    (~(PCI_BASE_ROM_ADDR_M & request))+1);
486810923SEvan.Yan@Sun.COM 		/*
486910923SEvan.Yan@Sun.COM 		 * Add to the "reg" property
487010923SEvan.Yan@Sun.COM 		 */
487110923SEvan.Yan@Sun.COM 		if (pcicfg_update_reg_prop(new_child,
487210923SEvan.Yan@Sun.COM 		    request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
487310923SEvan.Yan@Sun.COM 			goto failedchild;
487410923SEvan.Yan@Sun.COM 		}
487510923SEvan.Yan@Sun.COM 		/*
487610923SEvan.Yan@Sun.COM 		 * Add to "assigned-addresses" property
487710923SEvan.Yan@Sun.COM 		 */
487810923SEvan.Yan@Sun.COM 		size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
487910923SEvan.Yan@Sun.COM 		if (pcicfg_update_assigned_prop_value(new_child, size,
488010923SEvan.Yan@Sun.COM 		    base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
488110923SEvan.Yan@Sun.COM 			goto failedchild;
488210923SEvan.Yan@Sun.COM 		}
488310923SEvan.Yan@Sun.COM 	}
488410923SEvan.Yan@Sun.COM 
488510923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
488610923SEvan.Yan@Sun.COM 
488710923SEvan.Yan@Sun.COM failedchild:
488810923SEvan.Yan@Sun.COM 	return (PCICFG_FAILURE);
488910923SEvan.Yan@Sun.COM }
489010923SEvan.Yan@Sun.COM 
489110923SEvan.Yan@Sun.COM 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)489210923SEvan.Yan@Sun.COM pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
489311245SZhijun.Fu@Sun.COM 	uint_t *highest_bus, boolean_t is_pcie)
489410923SEvan.Yan@Sun.COM {
489510923SEvan.Yan@Sun.COM 	uint64_t next_bus;
489610923SEvan.Yan@Sun.COM 	uint_t new_bus, num_slots;
489710923SEvan.Yan@Sun.COM 	ndi_ra_request_t req;
489810923SEvan.Yan@Sun.COM 	int rval, i, j;
489910923SEvan.Yan@Sun.COM 	uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end;
490010923SEvan.Yan@Sun.COM 	uint64_t io_answer, io_base, io_alen, io_size, io_end;
490110923SEvan.Yan@Sun.COM 	uint64_t round_answer, round_len;
490210923SEvan.Yan@Sun.COM 	pcicfg_range_t range[PCICFG_RANGE_LEN];
490310923SEvan.Yan@Sun.COM 	int bus_range[2];
490410923SEvan.Yan@Sun.COM 	pcicfg_phdl_t phdl;
490510923SEvan.Yan@Sun.COM 	int count;
490610923SEvan.Yan@Sun.COM 	uint64_t pcibus_base, pcibus_alen;
490710923SEvan.Yan@Sun.COM 	uint64_t max_bus;
490810923SEvan.Yan@Sun.COM 	uint8_t pcie_device_type = 0;
490910923SEvan.Yan@Sun.COM 	dev_info_t *new_device;
491010923SEvan.Yan@Sun.COM 	int trans_device;
491110923SEvan.Yan@Sun.COM 	int ari_mode = B_FALSE;
491210923SEvan.Yan@Sun.COM 	int max_function = PCICFG_MAX_FUNCTION;
491310923SEvan.Yan@Sun.COM 
491410923SEvan.Yan@Sun.COM 	/*
491510923SEvan.Yan@Sun.COM 	 * Set "device_type" to "pci", the actual type will be set later
491610923SEvan.Yan@Sun.COM 	 * by pcicfg_set_busnode_props() below. This is needed as the
491710923SEvan.Yan@Sun.COM 	 * pcicfg_ra_free() below would update "available" property based
491810923SEvan.Yan@Sun.COM 	 * on "device_type".
491910923SEvan.Yan@Sun.COM 	 *
492010923SEvan.Yan@Sun.COM 	 * This code can be removed later after PCI configurator is changed
492110923SEvan.Yan@Sun.COM 	 * to use PCIRM, which automatically update properties upon allocation
492210923SEvan.Yan@Sun.COM 	 * and free, at that time we'll be able to remove the code inside
492310923SEvan.Yan@Sun.COM 	 * ndi_ra_alloc/free() which currently updates "available" property
492410923SEvan.Yan@Sun.COM 	 * for pci/pcie devices in pcie fabric.
492510923SEvan.Yan@Sun.COM 	 */
492610923SEvan.Yan@Sun.COM 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
492710923SEvan.Yan@Sun.COM 	    "device_type", "pci") != DDI_SUCCESS) {
492810923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set \"device_type\" props\n");
492910923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
493010923SEvan.Yan@Sun.COM 	}
493110923SEvan.Yan@Sun.COM 
493210923SEvan.Yan@Sun.COM 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
493310923SEvan.Yan@Sun.COM 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
493410923SEvan.Yan@Sun.COM 	req.ra_boundbase = 0;
493510923SEvan.Yan@Sun.COM 	req.ra_boundlen = PCICFG_MAX_BUS_DEPTH;
493610923SEvan.Yan@Sun.COM 	req.ra_len = PCICFG_MAX_BUS_DEPTH;
493710923SEvan.Yan@Sun.COM 	req.ra_align_mask = 0;  /* no alignment needed */
493810923SEvan.Yan@Sun.COM 
493910923SEvan.Yan@Sun.COM 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
494010923SEvan.Yan@Sun.COM 	    &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
494110923SEvan.Yan@Sun.COM 
494210923SEvan.Yan@Sun.COM 	if (rval != NDI_SUCCESS) {
494310923SEvan.Yan@Sun.COM 		if (rval == NDI_RA_PARTIAL_REQ) {
494410923SEvan.Yan@Sun.COM 			/*EMPTY*/
494510923SEvan.Yan@Sun.COM 			DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
494610923SEvan.Yan@Sun.COM 		} else {
494710923SEvan.Yan@Sun.COM 			DEBUG0(
494810923SEvan.Yan@Sun.COM 			    "Failed to allocate bus range for bridge\n");
494910923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
495010923SEvan.Yan@Sun.COM 		}
495110923SEvan.Yan@Sun.COM 	}
495210923SEvan.Yan@Sun.COM 
495310923SEvan.Yan@Sun.COM 	DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
495410923SEvan.Yan@Sun.COM 	    pcibus_base, pcibus_alen);
495510923SEvan.Yan@Sun.COM 
495610923SEvan.Yan@Sun.COM 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
495710923SEvan.Yan@Sun.COM 	    == NDI_FAILURE) {
495810923SEvan.Yan@Sun.COM 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
495910923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
496010923SEvan.Yan@Sun.COM 	}
496110923SEvan.Yan@Sun.COM 
496210923SEvan.Yan@Sun.COM 	/*
496310923SEvan.Yan@Sun.COM 	 * Put available bus range into the pool.
496410923SEvan.Yan@Sun.COM 	 * Take the first one for this bridge to use and don't give
496510923SEvan.Yan@Sun.COM 	 * to child.
496610923SEvan.Yan@Sun.COM 	 */
496710923SEvan.Yan@Sun.COM 	(void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
496810923SEvan.Yan@Sun.COM 	    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
496910923SEvan.Yan@Sun.COM 
497010923SEvan.Yan@Sun.COM 	next_bus = pcibus_base;
497110923SEvan.Yan@Sun.COM 	max_bus = pcibus_base + pcibus_alen - 1;
497210923SEvan.Yan@Sun.COM 
497310923SEvan.Yan@Sun.COM 	new_bus = next_bus;
497410923SEvan.Yan@Sun.COM 
497510923SEvan.Yan@Sun.COM 	DEBUG1("NEW bus found  ->[%d]\n", new_bus);
497610923SEvan.Yan@Sun.COM 
497710923SEvan.Yan@Sun.COM 	/* Keep track of highest bus for subordinate bus programming */
497810923SEvan.Yan@Sun.COM 	*highest_bus = new_bus;
497910923SEvan.Yan@Sun.COM 
498010923SEvan.Yan@Sun.COM 	/*
498110923SEvan.Yan@Sun.COM 	 * Allocate Memory Space for Bridge
498210923SEvan.Yan@Sun.COM 	 */
498310923SEvan.Yan@Sun.COM 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
498410923SEvan.Yan@Sun.COM 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
498510923SEvan.Yan@Sun.COM 	req.ra_boundbase = 0;
498610923SEvan.Yan@Sun.COM 	/*
498710923SEvan.Yan@Sun.COM 	 * Note: To support a 32b system, boundlen and len need to be
498810923SEvan.Yan@Sun.COM 	 * 32b quantities
498910923SEvan.Yan@Sun.COM 	 */
499010923SEvan.Yan@Sun.COM 	req.ra_boundlen = PCICFG_4GIG_LIMIT + 1;
499110923SEvan.Yan@Sun.COM 	req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */
499210923SEvan.Yan@Sun.COM 	req.ra_align_mask =
499310923SEvan.Yan@Sun.COM 	    PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
499410923SEvan.Yan@Sun.COM 
499510923SEvan.Yan@Sun.COM 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
499610923SEvan.Yan@Sun.COM 	    &mem_answer, &mem_alen,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
499710923SEvan.Yan@Sun.COM 
499810923SEvan.Yan@Sun.COM 	if (rval != NDI_SUCCESS) {
499910923SEvan.Yan@Sun.COM 		if (rval == NDI_RA_PARTIAL_REQ) {
500010923SEvan.Yan@Sun.COM 			/*EMPTY*/
500110923SEvan.Yan@Sun.COM 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
500210923SEvan.Yan@Sun.COM 		} else {
500310923SEvan.Yan@Sun.COM 			DEBUG0(
500410923SEvan.Yan@Sun.COM 			    "Failed to allocate memory for bridge\n");
500510923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
500610923SEvan.Yan@Sun.COM 		}
500710923SEvan.Yan@Sun.COM 	}
500810923SEvan.Yan@Sun.COM 
500910923SEvan.Yan@Sun.COM 	DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
501010923SEvan.Yan@Sun.COM 	    PCICFG_HIADDR(mem_answer),
501110923SEvan.Yan@Sun.COM 	    PCICFG_LOADDR(mem_answer),
501210923SEvan.Yan@Sun.COM 	    mem_alen);
501310923SEvan.Yan@Sun.COM 
501410923SEvan.Yan@Sun.COM 	if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
501510923SEvan.Yan@Sun.COM 		DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
501610923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
501710923SEvan.Yan@Sun.COM 	}
501810923SEvan.Yan@Sun.COM 
501910923SEvan.Yan@Sun.COM 	/*
502010923SEvan.Yan@Sun.COM 	 * Put available memory into the pool.
502110923SEvan.Yan@Sun.COM 	 */
502210923SEvan.Yan@Sun.COM 	(void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
502310923SEvan.Yan@Sun.COM 	    NDI_RA_PASS);
502410923SEvan.Yan@Sun.COM 
502510923SEvan.Yan@Sun.COM 	mem_base = mem_answer;
502610923SEvan.Yan@Sun.COM 
502710923SEvan.Yan@Sun.COM 	/*
502810923SEvan.Yan@Sun.COM 	 * Allocate I/O Space for Bridge
502910923SEvan.Yan@Sun.COM 	 */
503010923SEvan.Yan@Sun.COM 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
503110923SEvan.Yan@Sun.COM 	req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
503210923SEvan.Yan@Sun.COM 	req.ra_boundbase = 0;
503310923SEvan.Yan@Sun.COM 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
503410923SEvan.Yan@Sun.COM 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
503510923SEvan.Yan@Sun.COM 	req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
503610923SEvan.Yan@Sun.COM 
503710923SEvan.Yan@Sun.COM 	rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
503810923SEvan.Yan@Sun.COM 	    &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
503910923SEvan.Yan@Sun.COM 
504010923SEvan.Yan@Sun.COM 	if (rval != NDI_SUCCESS) {
504110923SEvan.Yan@Sun.COM 		if (rval == NDI_RA_PARTIAL_REQ) {
504210923SEvan.Yan@Sun.COM 			/*EMPTY*/
504310923SEvan.Yan@Sun.COM 			DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
504410923SEvan.Yan@Sun.COM 		} else {
504510923SEvan.Yan@Sun.COM 			DEBUG0("Failed to allocate io space for bridge\n");
504610923SEvan.Yan@Sun.COM 			io_base = io_answer = io_alen = 0;
504710923SEvan.Yan@Sun.COM 			/* return (PCICFG_FAILURE); */
504810923SEvan.Yan@Sun.COM 		}
504910923SEvan.Yan@Sun.COM 	}
505010923SEvan.Yan@Sun.COM 
505110923SEvan.Yan@Sun.COM 	if (io_alen) {
505210923SEvan.Yan@Sun.COM 		DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
505310923SEvan.Yan@Sun.COM 		    PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer),
505410923SEvan.Yan@Sun.COM 		    io_alen);
505510923SEvan.Yan@Sun.COM 
505610923SEvan.Yan@Sun.COM 		if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) ==
505710923SEvan.Yan@Sun.COM 		    NDI_FAILURE) {
505810923SEvan.Yan@Sun.COM 			DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
505910923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
506010923SEvan.Yan@Sun.COM 		}
506110923SEvan.Yan@Sun.COM 
506210923SEvan.Yan@Sun.COM 		/*
506310923SEvan.Yan@Sun.COM 		 * Put available I/O into the pool.
506410923SEvan.Yan@Sun.COM 		 */
506510923SEvan.Yan@Sun.COM 		(void) ndi_ra_free(new_child, io_answer, io_alen,
506610923SEvan.Yan@Sun.COM 		    NDI_RA_TYPE_IO, NDI_RA_PASS);
506710923SEvan.Yan@Sun.COM 		io_base = io_answer;
506810923SEvan.Yan@Sun.COM 	}
506910923SEvan.Yan@Sun.COM 
507010923SEvan.Yan@Sun.COM 	pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
507110923SEvan.Yan@Sun.COM 
507210923SEvan.Yan@Sun.COM 	/*
507310923SEvan.Yan@Sun.COM 	 * Setup "bus-range" property before onlining the bridge.
507410923SEvan.Yan@Sun.COM 	 */
507510923SEvan.Yan@Sun.COM 	bus_range[0] = new_bus;
507610923SEvan.Yan@Sun.COM 	bus_range[1] = max_bus;
507710923SEvan.Yan@Sun.COM 
507810923SEvan.Yan@Sun.COM 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
507910923SEvan.Yan@Sun.COM 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
508010923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set bus-range property");
508110923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
508210923SEvan.Yan@Sun.COM 	}
508310923SEvan.Yan@Sun.COM 
508410923SEvan.Yan@Sun.COM 	/*
508510923SEvan.Yan@Sun.COM 	 * Reset the secondary bus
508610923SEvan.Yan@Sun.COM 	 */
508710923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_BCNTRL,
508810923SEvan.Yan@Sun.COM 	    pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
508910923SEvan.Yan@Sun.COM 
509010923SEvan.Yan@Sun.COM 	drv_usecwait(100);
509110923SEvan.Yan@Sun.COM 
509210923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_BCNTRL,
509310923SEvan.Yan@Sun.COM 	    pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
509410923SEvan.Yan@Sun.COM 
509510923SEvan.Yan@Sun.COM 	/*
509610923SEvan.Yan@Sun.COM 	 * Program the memory base register with the
509710923SEvan.Yan@Sun.COM 	 * start of the memory range
509810923SEvan.Yan@Sun.COM 	 */
509910923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_MEM_BASE,
510010923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
510110923SEvan.Yan@Sun.COM 
510210923SEvan.Yan@Sun.COM 	/*
510310923SEvan.Yan@Sun.COM 	 * Program the memory limit register with the
510410923SEvan.Yan@Sun.COM 	 * end of the memory range.
510510923SEvan.Yan@Sun.COM 	 */
510610923SEvan.Yan@Sun.COM 
510710923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
510810923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(
510910923SEvan.Yan@Sun.COM 	    PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
511010923SEvan.Yan@Sun.COM 
511110923SEvan.Yan@Sun.COM 	/*
511210923SEvan.Yan@Sun.COM 	 * Allocate the chunk of memory (if any) not programmed into the
511310923SEvan.Yan@Sun.COM 	 * bridge because of the round down.
511410923SEvan.Yan@Sun.COM 	 */
511510923SEvan.Yan@Sun.COM 	if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
511610923SEvan.Yan@Sun.COM 	    != (mem_answer + mem_alen)) {
511710923SEvan.Yan@Sun.COM 		DEBUG0("Need to allocate Memory round off chunk\n");
511810923SEvan.Yan@Sun.COM 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
511910923SEvan.Yan@Sun.COM 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
512010923SEvan.Yan@Sun.COM 		req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
512110923SEvan.Yan@Sun.COM 		    PCICFG_MEMGRAN);
512210923SEvan.Yan@Sun.COM 		req.ra_len =  (mem_answer + mem_alen) -
512310923SEvan.Yan@Sun.COM 		    (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
512410923SEvan.Yan@Sun.COM 		    PCICFG_MEMGRAN));
512510923SEvan.Yan@Sun.COM 
512610923SEvan.Yan@Sun.COM 		(void) ndi_ra_alloc(new_child, &req,
512710923SEvan.Yan@Sun.COM 		    &round_answer, &round_len,  NDI_RA_TYPE_MEM, NDI_RA_PASS);
512810923SEvan.Yan@Sun.COM 	}
512910923SEvan.Yan@Sun.COM 
513010923SEvan.Yan@Sun.COM 	/*
513110923SEvan.Yan@Sun.COM 	 * Program the I/O Space Base
513210923SEvan.Yan@Sun.COM 	 */
513310923SEvan.Yan@Sun.COM 	pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
513410923SEvan.Yan@Sun.COM 	    PCICFG_HIBYTE(PCICFG_LOWORD(
513510923SEvan.Yan@Sun.COM 	    PCICFG_LOADDR(io_answer))));
513610923SEvan.Yan@Sun.COM 
513710923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
513810923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
513910923SEvan.Yan@Sun.COM 
514010923SEvan.Yan@Sun.COM 	/*
514110923SEvan.Yan@Sun.COM 	 * Program the I/O Space Limit
514210923SEvan.Yan@Sun.COM 	 */
514310923SEvan.Yan@Sun.COM 	pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
514410923SEvan.Yan@Sun.COM 	    PCICFG_HIBYTE(PCICFG_LOWORD(
514510923SEvan.Yan@Sun.COM 	    PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
514610923SEvan.Yan@Sun.COM 	    PCICFG_IOGRAN)))) - 1);
514710923SEvan.Yan@Sun.COM 
514810923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
514910923SEvan.Yan@Sun.COM 	    PCICFG_HIWORD(PCICFG_LOADDR(
515010923SEvan.Yan@Sun.COM 	    PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
515110923SEvan.Yan@Sun.COM 	    - 1);
515210923SEvan.Yan@Sun.COM 
515310923SEvan.Yan@Sun.COM 	/*
515410923SEvan.Yan@Sun.COM 	 * Allocate the chunk of I/O (if any) not programmed into the
515510923SEvan.Yan@Sun.COM 	 * bridge because of the round down.
515610923SEvan.Yan@Sun.COM 	 */
515710923SEvan.Yan@Sun.COM 	if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
515810923SEvan.Yan@Sun.COM 	    != (io_answer + io_alen)) {
515910923SEvan.Yan@Sun.COM 		DEBUG0("Need to allocate I/O round off chunk\n");
516010923SEvan.Yan@Sun.COM 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
516110923SEvan.Yan@Sun.COM 		req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
516210923SEvan.Yan@Sun.COM 		req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
516310923SEvan.Yan@Sun.COM 		    PCICFG_IOGRAN);
516410923SEvan.Yan@Sun.COM 		req.ra_len =  (io_answer + io_alen) -
516510923SEvan.Yan@Sun.COM 		    (PCICFG_ROUND_DOWN((io_answer + io_alen),
516610923SEvan.Yan@Sun.COM 		    PCICFG_IOGRAN));
516710923SEvan.Yan@Sun.COM 
516810923SEvan.Yan@Sun.COM 		(void) ndi_ra_alloc(new_child, &req,
516910923SEvan.Yan@Sun.COM 		    &round_answer, &round_len,  NDI_RA_TYPE_IO, NDI_RA_PASS);
517010923SEvan.Yan@Sun.COM 	}
517110923SEvan.Yan@Sun.COM 
517210923SEvan.Yan@Sun.COM 	/*
517310923SEvan.Yan@Sun.COM 	 * Setup "ranges" property before onlining the bridge.
517410923SEvan.Yan@Sun.COM 	 */
517510923SEvan.Yan@Sun.COM 	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
517610923SEvan.Yan@Sun.COM 
517710923SEvan.Yan@Sun.COM 	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
517810923SEvan.Yan@Sun.COM 	range[0].child_lo = range[0].parent_lo = io_base;
517910923SEvan.Yan@Sun.COM 	range[1].child_hi = range[1].parent_hi |=
518010923SEvan.Yan@Sun.COM 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
518110923SEvan.Yan@Sun.COM 	range[1].child_lo = range[1].parent_lo = mem_base;
518210923SEvan.Yan@Sun.COM 
518310923SEvan.Yan@Sun.COM 	range[0].size_lo = io_alen;
518410923SEvan.Yan@Sun.COM 	if (pcicfg_update_ranges_prop(new_child, &range[0])) {
518510923SEvan.Yan@Sun.COM 		DEBUG0("Failed to update ranges (io)\n");
518610923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
518710923SEvan.Yan@Sun.COM 	}
518810923SEvan.Yan@Sun.COM 	range[1].size_lo = mem_alen;
518910923SEvan.Yan@Sun.COM 	if (pcicfg_update_ranges_prop(new_child, &range[1])) {
519010923SEvan.Yan@Sun.COM 		DEBUG0("Failed to update ranges (memory)\n");
519110923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
519210923SEvan.Yan@Sun.COM 	}
519310923SEvan.Yan@Sun.COM 
519410923SEvan.Yan@Sun.COM 	/*
519510923SEvan.Yan@Sun.COM 	 * Clear status bits
519610923SEvan.Yan@Sun.COM 	 */
519710923SEvan.Yan@Sun.COM 	pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
519810923SEvan.Yan@Sun.COM 
519910923SEvan.Yan@Sun.COM 	/*
520010923SEvan.Yan@Sun.COM 	 * Turn off prefetchable range
520110923SEvan.Yan@Sun.COM 	 */
520210923SEvan.Yan@Sun.COM 	pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
520310923SEvan.Yan@Sun.COM 	pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
520410923SEvan.Yan@Sun.COM 	pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
520510923SEvan.Yan@Sun.COM 
520610923SEvan.Yan@Sun.COM 	/*
520710923SEvan.Yan@Sun.COM 	 * Needs to be set to this value
520810923SEvan.Yan@Sun.COM 	 */
520910923SEvan.Yan@Sun.COM 	pci_config_put8(h, PCI_CONF_ILINE, 0xf);
521010923SEvan.Yan@Sun.COM 
521110923SEvan.Yan@Sun.COM 	/* check our device_type as defined by Open Firmware */
521210923SEvan.Yan@Sun.COM 	if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
521310923SEvan.Yan@Sun.COM 		pcie_device_type = 1;
521410923SEvan.Yan@Sun.COM 
521510923SEvan.Yan@Sun.COM 	/*
521610923SEvan.Yan@Sun.COM 	 * Set bus properties
521710923SEvan.Yan@Sun.COM 	 */
521810923SEvan.Yan@Sun.COM 	if (pcicfg_set_busnode_props(new_child, pcie_device_type,
521910923SEvan.Yan@Sun.COM 	    (int)bus, (int)new_bus) != PCICFG_SUCCESS) {
522010923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set busnode props\n");
522110923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
522210923SEvan.Yan@Sun.COM 	}
522310923SEvan.Yan@Sun.COM 
522410923SEvan.Yan@Sun.COM 	(void) pcicfg_device_on(h);
522510923SEvan.Yan@Sun.COM 
522611245SZhijun.Fu@Sun.COM 	if (is_pcie)
522711387SSurya.Prakki@Sun.COM 		(void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
522810923SEvan.Yan@Sun.COM 	if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
522910923SEvan.Yan@Sun.COM 	    != NDI_SUCCESS) {
523010923SEvan.Yan@Sun.COM 		DEBUG0("Unable to online bridge\n");
523110923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
523210923SEvan.Yan@Sun.COM 	}
523310923SEvan.Yan@Sun.COM 
523410923SEvan.Yan@Sun.COM 	DEBUG0("Bridge is ONLINE\n");
523510923SEvan.Yan@Sun.COM 
523610923SEvan.Yan@Sun.COM 	/*
523710923SEvan.Yan@Sun.COM 	 * After a Reset, we need to wait 2^25 clock cycles before the
523810923SEvan.Yan@Sun.COM 	 * first Configuration access.  The worst case is 33MHz, which
523910923SEvan.Yan@Sun.COM 	 * is a 1 second wait.
524010923SEvan.Yan@Sun.COM 	 */
524110923SEvan.Yan@Sun.COM 	drv_usecwait(pcicfg_sec_reset_delay);
524210923SEvan.Yan@Sun.COM 
524310923SEvan.Yan@Sun.COM 	/*
524410923SEvan.Yan@Sun.COM 	 * Probe all children devices
524510923SEvan.Yan@Sun.COM 	 */
524610923SEvan.Yan@Sun.COM 	DEBUG0("Bridge Programming Complete - probe children\n");
524710923SEvan.Yan@Sun.COM 	ndi_devi_enter(new_child, &count);
524810923SEvan.Yan@Sun.COM 	for (i = 0; ((i < PCICFG_MAX_DEVICE) && (ari_mode == B_FALSE));
524910923SEvan.Yan@Sun.COM 	    i++) {
525010923SEvan.Yan@Sun.COM 		for (j = 0; j < max_function; ) {
525110923SEvan.Yan@Sun.COM 			if (ari_mode)
525210923SEvan.Yan@Sun.COM 				trans_device = j >> 3;
525310923SEvan.Yan@Sun.COM 			else
525410923SEvan.Yan@Sun.COM 				trans_device = i;
525510923SEvan.Yan@Sun.COM 
525610923SEvan.Yan@Sun.COM 			if ((rval = pcicfg_fcode_probe(new_child,
525711245SZhijun.Fu@Sun.COM 			    new_bus, trans_device, (j & 7), highest_bus,
525811245SZhijun.Fu@Sun.COM 			    0, is_pcie))
525910923SEvan.Yan@Sun.COM 			    != PCICFG_SUCCESS) {
526010923SEvan.Yan@Sun.COM 				if (rval == PCICFG_NODEVICE) {
526110923SEvan.Yan@Sun.COM 					DEBUG3("No Device at bus [0x%x]"
526210923SEvan.Yan@Sun.COM 					    "device [0x%x] "
526310923SEvan.Yan@Sun.COM 					    "func [0x%x]\n", new_bus,
526410923SEvan.Yan@Sun.COM 					    trans_device, j & 7);
526510923SEvan.Yan@Sun.COM 
526610923SEvan.Yan@Sun.COM 					if (j)
526710923SEvan.Yan@Sun.COM 						goto next;
526810923SEvan.Yan@Sun.COM 				} else {
526910923SEvan.Yan@Sun.COM 					DEBUG3("Failed to configure bus "
527010923SEvan.Yan@Sun.COM 					    "[0x%x] device [0x%x] "
527110923SEvan.Yan@Sun.COM 					    "func [0x%x]\n", new_bus,
527210923SEvan.Yan@Sun.COM 					    trans_device, j & 7);
527310923SEvan.Yan@Sun.COM 
527410923SEvan.Yan@Sun.COM 					rval = PCICFG_FAILURE;
527510923SEvan.Yan@Sun.COM 				}
527610923SEvan.Yan@Sun.COM 				break;
527710923SEvan.Yan@Sun.COM 			}
527810923SEvan.Yan@Sun.COM next:
527910923SEvan.Yan@Sun.COM 			new_device = pcicfg_devi_find(new_child,
528010923SEvan.Yan@Sun.COM 			    trans_device, (j & 7));
528110923SEvan.Yan@Sun.COM 
528210923SEvan.Yan@Sun.COM 			/*
528310923SEvan.Yan@Sun.COM 			 * Determine if ARI Forwarding should be enabled.
528410923SEvan.Yan@Sun.COM 			 */
528510923SEvan.Yan@Sun.COM 			if (j == 0) {
528610923SEvan.Yan@Sun.COM 				if (new_device == NULL)
528710923SEvan.Yan@Sun.COM 					break;
528810923SEvan.Yan@Sun.COM 
528910923SEvan.Yan@Sun.COM 				if ((pcie_ari_supported(new_child) ==
529010923SEvan.Yan@Sun.COM 				    PCIE_ARI_FORW_ENABLED) &&
529110923SEvan.Yan@Sun.COM 				    (pcie_ari_device(new_device) ==
529210923SEvan.Yan@Sun.COM 				    PCIE_ARI_DEVICE)) {
529310923SEvan.Yan@Sun.COM 					if (pcie_ari_enable(new_child) ==
529410923SEvan.Yan@Sun.COM 					    DDI_SUCCESS) {
529510923SEvan.Yan@Sun.COM 						(void) ddi_prop_create(
529610923SEvan.Yan@Sun.COM 						    DDI_DEV_T_NONE,
529710923SEvan.Yan@Sun.COM 						    new_child,
529810923SEvan.Yan@Sun.COM 						    DDI_PROP_CANSLEEP,
529910923SEvan.Yan@Sun.COM 						    "ari-enabled", NULL, 0);
530010923SEvan.Yan@Sun.COM 						ari_mode = B_TRUE;
530110923SEvan.Yan@Sun.COM 						max_function =
530210923SEvan.Yan@Sun.COM 						    PCICFG_MAX_ARI_FUNCTION;
530310923SEvan.Yan@Sun.COM 					}
530410923SEvan.Yan@Sun.COM 				}
530510923SEvan.Yan@Sun.COM 			}
530610923SEvan.Yan@Sun.COM 
530710923SEvan.Yan@Sun.COM 			if (ari_mode == B_TRUE) {
530810923SEvan.Yan@Sun.COM 				int next_function;
530910923SEvan.Yan@Sun.COM 
531010923SEvan.Yan@Sun.COM 				if (new_device == NULL)
531110923SEvan.Yan@Sun.COM 					break;
531210923SEvan.Yan@Sun.COM 
531310923SEvan.Yan@Sun.COM 				if (pcie_ari_get_next_function(new_device,
531410923SEvan.Yan@Sun.COM 				    &next_function) != DDI_SUCCESS)
531510923SEvan.Yan@Sun.COM 					break;
531610923SEvan.Yan@Sun.COM 
531710923SEvan.Yan@Sun.COM 				j = next_function;
531810923SEvan.Yan@Sun.COM 
531910923SEvan.Yan@Sun.COM 				if (next_function == 0)
532010923SEvan.Yan@Sun.COM 					break;
532110923SEvan.Yan@Sun.COM 			} else
532210923SEvan.Yan@Sun.COM 				j++;
532310923SEvan.Yan@Sun.COM 		}
532410923SEvan.Yan@Sun.COM 	}
532510923SEvan.Yan@Sun.COM 
532610923SEvan.Yan@Sun.COM 	ndi_devi_exit(new_child, count);
532710923SEvan.Yan@Sun.COM 
532810923SEvan.Yan@Sun.COM 	/* if empty topology underneath, it is still a success. */
532910923SEvan.Yan@Sun.COM 	if (rval != PCICFG_FAILURE)
533010923SEvan.Yan@Sun.COM 		rval = PCICFG_SUCCESS;
533110923SEvan.Yan@Sun.COM 
533210923SEvan.Yan@Sun.COM 	/*
533310923SEvan.Yan@Sun.COM 	 * Offline the bridge to allow reprogramming of resources.
533410923SEvan.Yan@Sun.COM 	 *
533510923SEvan.Yan@Sun.COM 	 * This should always succeed since nobody else has started to
533610923SEvan.Yan@Sun.COM 	 * use it yet, failing to detach the driver would indicate a bug.
533710923SEvan.Yan@Sun.COM 	 * Also in that case it's better just panic than allowing the
533810923SEvan.Yan@Sun.COM 	 * configurator to proceed with BAR reprogramming without bridge
533910923SEvan.Yan@Sun.COM 	 * driver detached.
534010923SEvan.Yan@Sun.COM 	 */
534110923SEvan.Yan@Sun.COM 	VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
534210923SEvan.Yan@Sun.COM 	    == NDI_SUCCESS);
534311245SZhijun.Fu@Sun.COM 	if (is_pcie)
534411245SZhijun.Fu@Sun.COM 		pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
534510923SEvan.Yan@Sun.COM 
534610923SEvan.Yan@Sun.COM 	phdl.dip = new_child;
534710923SEvan.Yan@Sun.COM 	phdl.memory_base = mem_answer;
534810923SEvan.Yan@Sun.COM 	phdl.io_base = (uint32_t)io_answer;
534910923SEvan.Yan@Sun.COM 	phdl.error = PCICFG_SUCCESS;    /* in case of empty child tree */
535010923SEvan.Yan@Sun.COM 
535110923SEvan.Yan@Sun.COM 	ndi_devi_enter(ddi_get_parent(new_child), &count);
535210923SEvan.Yan@Sun.COM 	ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
535310923SEvan.Yan@Sun.COM 	ndi_devi_exit(ddi_get_parent(new_child), count);
535410923SEvan.Yan@Sun.COM 
535510923SEvan.Yan@Sun.COM 	if (phdl.error != PCICFG_SUCCESS) {
535610923SEvan.Yan@Sun.COM 		DEBUG0("Failure summing resources\n");
535710923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
535810923SEvan.Yan@Sun.COM 	}
535910923SEvan.Yan@Sun.COM 
536010923SEvan.Yan@Sun.COM 	num_slots = pcicfg_get_nslots(new_child, h);
536110923SEvan.Yan@Sun.COM 	mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
536210923SEvan.Yan@Sun.COM 	io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
536310923SEvan.Yan@Sun.COM 
536410923SEvan.Yan@Sun.COM 	DEBUG3("Start of Unallocated Bridge(%d slots) Resources "
536510923SEvan.Yan@Sun.COM 	    "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end);
536610923SEvan.Yan@Sun.COM 
536710923SEvan.Yan@Sun.COM 	/*
536810923SEvan.Yan@Sun.COM 	 * Before probing the children we've allocated maximum MEM/IO
536910923SEvan.Yan@Sun.COM 	 * resources from parent, and updated "available" property
537010923SEvan.Yan@Sun.COM 	 * accordingly. Later we'll be giving up unused resources to
537110923SEvan.Yan@Sun.COM 	 * the parent, thus we need to destroy "available" property
537210923SEvan.Yan@Sun.COM 	 * here otherwise it will be out-of-sync with the actual free
537310923SEvan.Yan@Sun.COM 	 * resources this bridge has. This property will be rebuilt below
537410923SEvan.Yan@Sun.COM 	 * with the actual free resources reserved for hotplug slots
537510923SEvan.Yan@Sun.COM 	 * (if any).
537610923SEvan.Yan@Sun.COM 	 */
537710923SEvan.Yan@Sun.COM 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
537810923SEvan.Yan@Sun.COM 	/*
537910923SEvan.Yan@Sun.COM 	 * if the bridge a slots, then preallocate. If not, assume static
538010923SEvan.Yan@Sun.COM 	 * configuration. Also check for preallocation limits and spit
538110923SEvan.Yan@Sun.COM 	 * warning messages appropriately (perhaps some can be in debug mode).
538210923SEvan.Yan@Sun.COM 	 */
538310923SEvan.Yan@Sun.COM 	if (num_slots) {
538410923SEvan.Yan@Sun.COM 		pci_regspec_t reg;
538510923SEvan.Yan@Sun.COM 		uint64_t mem_assigned = mem_end;
538610923SEvan.Yan@Sun.COM 		uint64_t io_assigned = io_end;
538710923SEvan.Yan@Sun.COM 		uint64_t mem_reqd = mem_answer + (num_slots *
538810923SEvan.Yan@Sun.COM 		    pcicfg_slot_memsize);
538910923SEvan.Yan@Sun.COM 		uint64_t io_reqd = io_answer + (num_slots *
539010923SEvan.Yan@Sun.COM 		    pcicfg_slot_iosize);
539110923SEvan.Yan@Sun.COM 		uint8_t highest_bus_reqd = new_bus + (num_slots *
539210923SEvan.Yan@Sun.COM 		    pcicfg_slot_busnums);
539310923SEvan.Yan@Sun.COM #ifdef DEBUG
539410923SEvan.Yan@Sun.COM 		if (mem_end > mem_reqd)
539510923SEvan.Yan@Sun.COM 			DEBUG3("Memory space consumed by bridge"
539610923SEvan.Yan@Sun.COM 			    " more than planned for %d slot(s)(%lx, %lx)",
539710923SEvan.Yan@Sun.COM 			    num_slots, mem_answer, mem_end);
539810923SEvan.Yan@Sun.COM 		if (io_end > io_reqd)
539910923SEvan.Yan@Sun.COM 			DEBUG3("IO space consumed by bridge"
540010923SEvan.Yan@Sun.COM 			    " more than planned for %d slot(s)(%lx, %lx)",
540110923SEvan.Yan@Sun.COM 			    num_slots, io_answer, io_end);
540210923SEvan.Yan@Sun.COM 		if (*highest_bus > highest_bus_reqd)
540310923SEvan.Yan@Sun.COM 			DEBUG3("Buses consumed by bridge"
540410923SEvan.Yan@Sun.COM 			    " more than planned for %d slot(s)(%x, %x)",
540510923SEvan.Yan@Sun.COM 			    num_slots, new_bus, *highest_bus);
540610923SEvan.Yan@Sun.COM 
540710923SEvan.Yan@Sun.COM 		if (mem_reqd > (mem_answer + mem_alen))
540810923SEvan.Yan@Sun.COM 			DEBUG3("Memory space required by bridge"
540910923SEvan.Yan@Sun.COM 			    " more than available for %d slot(s)(%lx, %lx)",
541010923SEvan.Yan@Sun.COM 			    num_slots, mem_answer, mem_end);
541110923SEvan.Yan@Sun.COM 
541210923SEvan.Yan@Sun.COM 		if (io_reqd > (io_answer + io_alen))
541310923SEvan.Yan@Sun.COM 			DEBUG3("IO space required by bridge"
541410923SEvan.Yan@Sun.COM 			    " more than available for %d slot(s)(%lx, %lx)",
541510923SEvan.Yan@Sun.COM 			    num_slots, io_answer, io_end);
541610923SEvan.Yan@Sun.COM 		if (highest_bus_reqd > max_bus)
541710923SEvan.Yan@Sun.COM 			DEBUG3("Bus numbers required by bridge"
541810923SEvan.Yan@Sun.COM 			    " more than available for %d slot(s)(%x, %x)",
541910923SEvan.Yan@Sun.COM 			    num_slots, new_bus, *highest_bus);
542010923SEvan.Yan@Sun.COM #endif
542110923SEvan.Yan@Sun.COM 		mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
542210923SEvan.Yan@Sun.COM 		    mem_end);
542310923SEvan.Yan@Sun.COM 		io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
542410923SEvan.Yan@Sun.COM 		*highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
542510923SEvan.Yan@Sun.COM 		    *highest_bus);
542610923SEvan.Yan@Sun.COM 		DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n",
542710923SEvan.Yan@Sun.COM 		    mem_end, io_end, *highest_bus);
542810923SEvan.Yan@Sun.COM 
542910923SEvan.Yan@Sun.COM 		mem_size = mem_end - mem_assigned;
543010923SEvan.Yan@Sun.COM 		io_size = io_end - io_assigned;
543110923SEvan.Yan@Sun.COM 
543210923SEvan.Yan@Sun.COM 		reg.pci_phys_mid = reg.pci_size_hi = 0;
543310923SEvan.Yan@Sun.COM 		if (io_size > 0) {
543410923SEvan.Yan@Sun.COM 			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO);
543510923SEvan.Yan@Sun.COM 			reg.pci_phys_low = io_assigned;
543610923SEvan.Yan@Sun.COM 			reg.pci_size_low = io_size;
543710923SEvan.Yan@Sun.COM 			if (pcicfg_update_available_prop(new_child, &reg)) {
543810923SEvan.Yan@Sun.COM 				DEBUG0("Failed to update available prop "
543910923SEvan.Yan@Sun.COM 				    "(io)\n");
544010923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
544110923SEvan.Yan@Sun.COM 			}
544210923SEvan.Yan@Sun.COM 		}
544310923SEvan.Yan@Sun.COM 		if (mem_size > 0) {
544410923SEvan.Yan@Sun.COM 			reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32);
544510923SEvan.Yan@Sun.COM 			reg.pci_phys_low = mem_assigned;
544610923SEvan.Yan@Sun.COM 			reg.pci_size_low = mem_size;
544710923SEvan.Yan@Sun.COM 			if (pcicfg_update_available_prop(new_child, &reg)) {
544810923SEvan.Yan@Sun.COM 				DEBUG0("Failed to update available prop "
544910923SEvan.Yan@Sun.COM 				    "(memory)\n");
545010923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
545110923SEvan.Yan@Sun.COM 			}
545210923SEvan.Yan@Sun.COM 		}
545310923SEvan.Yan@Sun.COM 	}
545410923SEvan.Yan@Sun.COM 
545510923SEvan.Yan@Sun.COM 	/*
545610923SEvan.Yan@Sun.COM 	 * Give back unused memory space to parent.
545710923SEvan.Yan@Sun.COM 	 */
545810923SEvan.Yan@Sun.COM 	(void) ndi_ra_free(ddi_get_parent(new_child),
545910923SEvan.Yan@Sun.COM 	    mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
546010923SEvan.Yan@Sun.COM 	    NDI_RA_PASS);
546110923SEvan.Yan@Sun.COM 
546210923SEvan.Yan@Sun.COM 	if (mem_end == mem_answer) {
546310923SEvan.Yan@Sun.COM 		DEBUG0("No memory resources used\n");
546410923SEvan.Yan@Sun.COM 		/*
546510923SEvan.Yan@Sun.COM 		 * To prevent the bridge from forwarding any Memory
546610923SEvan.Yan@Sun.COM 		 * transactions, the Memory Limit will be programmed
546710923SEvan.Yan@Sun.COM 		 * with a smaller value than the Memory Base.
546810923SEvan.Yan@Sun.COM 		 */
546910923SEvan.Yan@Sun.COM 		pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
547010923SEvan.Yan@Sun.COM 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
547110923SEvan.Yan@Sun.COM 
547210923SEvan.Yan@Sun.COM 		mem_size = 0;
547310923SEvan.Yan@Sun.COM 	} else {
547410923SEvan.Yan@Sun.COM 		/*
547510923SEvan.Yan@Sun.COM 		 * Reprogram the end of the memory.
547610923SEvan.Yan@Sun.COM 		 */
547710923SEvan.Yan@Sun.COM 		pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
547810923SEvan.Yan@Sun.COM 		    PCICFG_HIWORD(mem_end) - 1);
547910923SEvan.Yan@Sun.COM 		mem_size = mem_end - mem_base;
548010923SEvan.Yan@Sun.COM 	}
548110923SEvan.Yan@Sun.COM 
548210923SEvan.Yan@Sun.COM 	/*
548310923SEvan.Yan@Sun.COM 	 * Give back unused io space to parent.
548410923SEvan.Yan@Sun.COM 	 */
548510923SEvan.Yan@Sun.COM 	(void) ndi_ra_free(ddi_get_parent(new_child),
548610923SEvan.Yan@Sun.COM 	    io_end, (io_answer + io_alen) - io_end,
548710923SEvan.Yan@Sun.COM 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
548810923SEvan.Yan@Sun.COM 
548910923SEvan.Yan@Sun.COM 	if (io_end == io_answer) {
549010923SEvan.Yan@Sun.COM 		DEBUG0("No IO Space resources used\n");
549110923SEvan.Yan@Sun.COM 
549210923SEvan.Yan@Sun.COM 		/*
549310923SEvan.Yan@Sun.COM 		 * To prevent the bridge from forwarding any I/O
549410923SEvan.Yan@Sun.COM 		 * transactions, the I/O Limit will be programmed
549510923SEvan.Yan@Sun.COM 		 * with a smaller value than the I/O Base.
549610923SEvan.Yan@Sun.COM 		 */
549710923SEvan.Yan@Sun.COM 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
549810923SEvan.Yan@Sun.COM 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
549910923SEvan.Yan@Sun.COM 		pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
550010923SEvan.Yan@Sun.COM 		pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
550110923SEvan.Yan@Sun.COM 
550210923SEvan.Yan@Sun.COM 		io_size = 0;
550310923SEvan.Yan@Sun.COM 	} else {
550410923SEvan.Yan@Sun.COM 		/*
550510923SEvan.Yan@Sun.COM 		 * Reprogram the end of the io space.
550610923SEvan.Yan@Sun.COM 		 */
550710923SEvan.Yan@Sun.COM 		pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
550810923SEvan.Yan@Sun.COM 		    PCICFG_HIBYTE(PCICFG_LOWORD(
550910923SEvan.Yan@Sun.COM 		    PCICFG_LOADDR(io_end) - 1)));
551010923SEvan.Yan@Sun.COM 
551110923SEvan.Yan@Sun.COM 		pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
551210923SEvan.Yan@Sun.COM 		    PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
551310923SEvan.Yan@Sun.COM 
551410923SEvan.Yan@Sun.COM 		io_size = io_end - io_base;
551510923SEvan.Yan@Sun.COM 	}
551610923SEvan.Yan@Sun.COM 
551710923SEvan.Yan@Sun.COM 	if ((max_bus - *highest_bus) > 0) {
551810923SEvan.Yan@Sun.COM 		/*
551910923SEvan.Yan@Sun.COM 		 * Give back unused bus numbers
552010923SEvan.Yan@Sun.COM 		 */
552110923SEvan.Yan@Sun.COM 		(void) ndi_ra_free(ddi_get_parent(new_child),
552210923SEvan.Yan@Sun.COM 		    *highest_bus+1, max_bus - *highest_bus,
552310923SEvan.Yan@Sun.COM 		    NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
552410923SEvan.Yan@Sun.COM 	}
552510923SEvan.Yan@Sun.COM 
552610923SEvan.Yan@Sun.COM 	/*
552710923SEvan.Yan@Sun.COM 	 * Set bus numbers to ranges encountered during scan
552810923SEvan.Yan@Sun.COM 	 */
552910923SEvan.Yan@Sun.COM 	pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
553010923SEvan.Yan@Sun.COM 
553110923SEvan.Yan@Sun.COM 	bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
553210923SEvan.Yan@Sun.COM 	bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
553310923SEvan.Yan@Sun.COM 	DEBUG1("End of bridge probe: bus_range[0] =  %d\n", bus_range[0]);
553410923SEvan.Yan@Sun.COM 	DEBUG1("End of bridge probe: bus_range[1] =  %d\n", bus_range[1]);
553510923SEvan.Yan@Sun.COM 
553610923SEvan.Yan@Sun.COM 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
553710923SEvan.Yan@Sun.COM 	    "bus-range", bus_range, 2) != DDI_SUCCESS) {
553810923SEvan.Yan@Sun.COM 		DEBUG0("Failed to set bus-range property");
553910923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
554010923SEvan.Yan@Sun.COM 	}
554110923SEvan.Yan@Sun.COM 
554210923SEvan.Yan@Sun.COM 	/*
554310923SEvan.Yan@Sun.COM 	 * Remove the ranges property if it exists since we will create
554410923SEvan.Yan@Sun.COM 	 * a new one.
554510923SEvan.Yan@Sun.COM 	 */
554610923SEvan.Yan@Sun.COM 	(void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
554710923SEvan.Yan@Sun.COM 
554810923SEvan.Yan@Sun.COM 	DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
554910923SEvan.Yan@Sun.COM 	    mem_base, mem_size);
555010923SEvan.Yan@Sun.COM 	DEBUG2("                         - I/O Address %lx I/O Size %x\n",
555110923SEvan.Yan@Sun.COM 	    io_base, io_size);
555210923SEvan.Yan@Sun.COM 
555310923SEvan.Yan@Sun.COM 	bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
555410923SEvan.Yan@Sun.COM 
555510923SEvan.Yan@Sun.COM 	range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
555610923SEvan.Yan@Sun.COM 	range[0].child_lo = range[0].parent_lo = io_base;
555710923SEvan.Yan@Sun.COM 	range[1].child_hi = range[1].parent_hi |=
555810923SEvan.Yan@Sun.COM 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
555910923SEvan.Yan@Sun.COM 	range[1].child_lo = range[1].parent_lo = mem_base;
556010923SEvan.Yan@Sun.COM 
556110923SEvan.Yan@Sun.COM 	if (io_size > 0) {
556210923SEvan.Yan@Sun.COM 		range[0].size_lo = io_size;
556310923SEvan.Yan@Sun.COM 		if (pcicfg_update_ranges_prop(new_child, &range[0])) {
556410923SEvan.Yan@Sun.COM 			DEBUG0("Failed to update ranges (io)\n");
556510923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
556610923SEvan.Yan@Sun.COM 		}
556710923SEvan.Yan@Sun.COM 	}
556810923SEvan.Yan@Sun.COM 	if (mem_size > 0) {
556910923SEvan.Yan@Sun.COM 		range[1].size_lo = mem_size;
557010923SEvan.Yan@Sun.COM 		if (pcicfg_update_ranges_prop(new_child, &range[1])) {
557110923SEvan.Yan@Sun.COM 			DEBUG0("Failed to update ranges (memory)\n");
557210923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
557310923SEvan.Yan@Sun.COM 		}
557410923SEvan.Yan@Sun.COM 	}
557510923SEvan.Yan@Sun.COM 
557610923SEvan.Yan@Sun.COM 	/*
557710923SEvan.Yan@Sun.COM 	 * Remove the resource maps for the bridge since we no longer
557810923SEvan.Yan@Sun.COM 	 * need them.  Note that the failure is ignored since the
557910923SEvan.Yan@Sun.COM 	 * ndi_devi_offline above may have already taken care of it via
558010923SEvan.Yan@Sun.COM 	 * driver detach.
558110923SEvan.Yan@Sun.COM 	 * It has been checked that there are no other reasons for
558210923SEvan.Yan@Sun.COM 	 * failure other than map itself being non-existent. So we are Ok.
558310923SEvan.Yan@Sun.COM 	 */
558410923SEvan.Yan@Sun.COM 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
558510923SEvan.Yan@Sun.COM 		/*EMPTY*/
558610923SEvan.Yan@Sun.COM 		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n");
558710923SEvan.Yan@Sun.COM 	}
558810923SEvan.Yan@Sun.COM 
558910923SEvan.Yan@Sun.COM 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
559010923SEvan.Yan@Sun.COM 		/*EMPTY*/
559110923SEvan.Yan@Sun.COM 		DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n");
559210923SEvan.Yan@Sun.COM 	}
559310923SEvan.Yan@Sun.COM 
559410923SEvan.Yan@Sun.COM 	if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM)
559510923SEvan.Yan@Sun.COM 	    == NDI_FAILURE) {
559610923SEvan.Yan@Sun.COM 		/*EMPTY*/
559710923SEvan.Yan@Sun.COM 		DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
559810923SEvan.Yan@Sun.COM 	}
559910923SEvan.Yan@Sun.COM 
560010923SEvan.Yan@Sun.COM 	return (rval);
560110923SEvan.Yan@Sun.COM }
560210923SEvan.Yan@Sun.COM 
560310923SEvan.Yan@Sun.COM /*
560410923SEvan.Yan@Sun.COM  * Return PCICFG_SUCCESS if device exists at the specified address.
560510923SEvan.Yan@Sun.COM  * Return PCICFG_NODEVICE is no device exists at the specified address.
560610923SEvan.Yan@Sun.COM  *
560710923SEvan.Yan@Sun.COM  */
560810923SEvan.Yan@Sun.COM int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)560910923SEvan.Yan@Sun.COM pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
561010923SEvan.Yan@Sun.COM {
561110923SEvan.Yan@Sun.COM 	caddr_t			virt;
561210923SEvan.Yan@Sun.COM 	ddi_device_acc_attr_t	attr;
561310923SEvan.Yan@Sun.COM 	int			status;
561410923SEvan.Yan@Sun.COM 	int			rlen;
561510923SEvan.Yan@Sun.COM 	pci_regspec_t		*reg;
561610923SEvan.Yan@Sun.COM 	int			ret = DDI_SUCCESS;
561710923SEvan.Yan@Sun.COM 	int16_t			tmp;
561810923SEvan.Yan@Sun.COM 	/*
561910923SEvan.Yan@Sun.COM 	 * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly
562010923SEvan.Yan@Sun.COM 	 * mapped, otherwise it is 0. "flags" is introduced in support of any
562110923SEvan.Yan@Sun.COM 	 * non transparent bridges, where configuration space is indirectly
562210923SEvan.Yan@Sun.COM 	 * mapped.
562310923SEvan.Yan@Sun.COM 	 * Indirect mapping is always true on sun4v systems.
562410923SEvan.Yan@Sun.COM 	 */
562510923SEvan.Yan@Sun.COM 	int			flags = 0;
562610923SEvan.Yan@Sun.COM 
562710923SEvan.Yan@Sun.COM 
562810923SEvan.Yan@Sun.COM 	/*
562910923SEvan.Yan@Sun.COM 	 * Get the pci register spec from the node
563010923SEvan.Yan@Sun.COM 	 */
563110923SEvan.Yan@Sun.COM 	status = ddi_getlongprop(DDI_DEV_T_ANY,
563210923SEvan.Yan@Sun.COM 	    dip, DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &rlen);
563310923SEvan.Yan@Sun.COM 
563410923SEvan.Yan@Sun.COM 	switch (status) {
563510923SEvan.Yan@Sun.COM 		case DDI_PROP_SUCCESS:
563610923SEvan.Yan@Sun.COM 		break;
563710923SEvan.Yan@Sun.COM 		case DDI_PROP_NO_MEMORY:
563810923SEvan.Yan@Sun.COM 			DEBUG0("reg present, but unable to get memory\n");
563910923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
564010923SEvan.Yan@Sun.COM 		default:
564110923SEvan.Yan@Sun.COM 			DEBUG0("no reg property\n");
564210923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
564310923SEvan.Yan@Sun.COM 	}
564410923SEvan.Yan@Sun.COM 
564510923SEvan.Yan@Sun.COM 	if (pcicfg_indirect_map(dip) == DDI_SUCCESS)
564610923SEvan.Yan@Sun.COM 		flags |= PCICFG_CONF_INDIRECT_MAP;
564710923SEvan.Yan@Sun.COM 
564810923SEvan.Yan@Sun.COM 	/*
564910923SEvan.Yan@Sun.COM 	 * Map in configuration space (temporarily)
565010923SEvan.Yan@Sun.COM 	 */
565110923SEvan.Yan@Sun.COM 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
565210923SEvan.Yan@Sun.COM 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
565310923SEvan.Yan@Sun.COM 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
565410923SEvan.Yan@Sun.COM 	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
565510923SEvan.Yan@Sun.COM 
565610923SEvan.Yan@Sun.COM #ifdef	EFCODE21554
565710923SEvan.Yan@Sun.COM 	if (ddi_regs_map_setup(dip, 0, &virt,
565810923SEvan.Yan@Sun.COM 	    0, 0, &attr, handle) != DDI_SUCCESS)
565910923SEvan.Yan@Sun.COM #else
566010923SEvan.Yan@Sun.COM 	if (pcicfg_map_phys(dip, reg, &virt, &attr, handle)
566110923SEvan.Yan@Sun.COM 	    != DDI_SUCCESS)
566210923SEvan.Yan@Sun.COM #endif
566310923SEvan.Yan@Sun.COM 	{
566410923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_config_setup():"
566510923SEvan.Yan@Sun.COM 		"Failed to setup config space\n");
566610923SEvan.Yan@Sun.COM 
566710923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)reg, rlen);
566810923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
566910923SEvan.Yan@Sun.COM 	}
567010923SEvan.Yan@Sun.COM 
567110923SEvan.Yan@Sun.COM 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
567210923SEvan.Yan@Sun.COM 		/*
567310923SEvan.Yan@Sun.COM 		 * need to use DDI interfaces as the conf space is
567410923SEvan.Yan@Sun.COM 		 * cannot be directly accessed by the host.
567510923SEvan.Yan@Sun.COM 		 */
567610923SEvan.Yan@Sun.COM 		tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt);
567710923SEvan.Yan@Sun.COM 	} else {
567810923SEvan.Yan@Sun.COM 		ret = ddi_peek16(dip, (int16_t *)virt, &tmp);
567910923SEvan.Yan@Sun.COM 	}
568010923SEvan.Yan@Sun.COM 
568110923SEvan.Yan@Sun.COM 	if (ret == DDI_SUCCESS) {
568210923SEvan.Yan@Sun.COM 		if (tmp == -1) {
568310923SEvan.Yan@Sun.COM 			DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
568410923SEvan.Yan@Sun.COM 			ret = PCICFG_NODEVICE;
568510923SEvan.Yan@Sun.COM 		} else {
568610923SEvan.Yan@Sun.COM 			/* XXX - Need to check why HV is returning 0 */
568710923SEvan.Yan@Sun.COM 			if (tmp == 0) {
568810923SEvan.Yan@Sun.COM 				DEBUG0("Device Not Ready yet ?");
568910923SEvan.Yan@Sun.COM 				ret = PCICFG_NODEVICE;
569010923SEvan.Yan@Sun.COM 			} else {
569110923SEvan.Yan@Sun.COM 				DEBUG1("DEVICEFOUND, read %x\n", tmp);
569210923SEvan.Yan@Sun.COM 				ret = PCICFG_SUCCESS;
569310923SEvan.Yan@Sun.COM 			}
569410923SEvan.Yan@Sun.COM 		}
569510923SEvan.Yan@Sun.COM 	} else {
569610923SEvan.Yan@Sun.COM 		DEBUG0("ddi_peek failed, must be NODEVICE\n");
569710923SEvan.Yan@Sun.COM 		ret = PCICFG_NODEVICE;
569810923SEvan.Yan@Sun.COM 	}
569910923SEvan.Yan@Sun.COM 
570010923SEvan.Yan@Sun.COM 	/*
570110923SEvan.Yan@Sun.COM 	 * A bug in XMITS 3.0 causes us to miss the Master Abort Split
570210923SEvan.Yan@Sun.COM 	 * Completion message.  The result is the error message being
570310923SEvan.Yan@Sun.COM 	 * sent back as part of the config data.  If the first two words
570410923SEvan.Yan@Sun.COM 	 * of the config space happen to be the same as the Master Abort
570510923SEvan.Yan@Sun.COM 	 * message, then report back that there is no device there.
570610923SEvan.Yan@Sun.COM 	 */
570710923SEvan.Yan@Sun.COM 	if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) {
570810923SEvan.Yan@Sun.COM 		int32_t	pcix_scm;
570910923SEvan.Yan@Sun.COM 
571010923SEvan.Yan@Sun.COM #define		PCICFG_PCIX_SCM	0x10000004
571110923SEvan.Yan@Sun.COM 
571210923SEvan.Yan@Sun.COM 		pcix_scm = 0;
571310923SEvan.Yan@Sun.COM 		(void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm);
571410923SEvan.Yan@Sun.COM 		if (pcix_scm == PCICFG_PCIX_SCM) {
571510923SEvan.Yan@Sun.COM 			pcix_scm = 0;
571610923SEvan.Yan@Sun.COM 			(void) ddi_peek32(dip,
571710923SEvan.Yan@Sun.COM 			    (int32_t *)(virt + 4), &pcix_scm);
571810923SEvan.Yan@Sun.COM 			if (pcix_scm == PCICFG_PCIX_SCM)
571910923SEvan.Yan@Sun.COM 				ret = PCICFG_NODEVICE;
572010923SEvan.Yan@Sun.COM 		}
572110923SEvan.Yan@Sun.COM 	}
572210923SEvan.Yan@Sun.COM 
572310923SEvan.Yan@Sun.COM 	if (ret == PCICFG_NODEVICE)
572410923SEvan.Yan@Sun.COM #ifdef	EFCODE21554
572510923SEvan.Yan@Sun.COM 		ddi_regs_map_free(handle);
572610923SEvan.Yan@Sun.COM #else
572710923SEvan.Yan@Sun.COM 		pcicfg_unmap_phys(handle, reg);
572810923SEvan.Yan@Sun.COM #endif
572910923SEvan.Yan@Sun.COM 
573010923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)reg, rlen);
573110923SEvan.Yan@Sun.COM 
573210923SEvan.Yan@Sun.COM 	return (ret);
573310923SEvan.Yan@Sun.COM 
573410923SEvan.Yan@Sun.COM }
573510923SEvan.Yan@Sun.COM 
573610923SEvan.Yan@Sun.COM static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)573710923SEvan.Yan@Sun.COM pcicfg_config_teardown(ddi_acc_handle_t *handle)
573810923SEvan.Yan@Sun.COM {
573910923SEvan.Yan@Sun.COM 	(void) ddi_regs_map_free(handle);
574010923SEvan.Yan@Sun.COM }
574110923SEvan.Yan@Sun.COM 
574210923SEvan.Yan@Sun.COM static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)574310923SEvan.Yan@Sun.COM pcicfg_add_config_reg(dev_info_t *dip,
574410923SEvan.Yan@Sun.COM 	uint_t bus, uint_t device, uint_t func)
574510923SEvan.Yan@Sun.COM {
574610923SEvan.Yan@Sun.COM 	int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
574710923SEvan.Yan@Sun.COM 
574810923SEvan.Yan@Sun.COM 	reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
574910923SEvan.Yan@Sun.COM 
575010923SEvan.Yan@Sun.COM 	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
575110923SEvan.Yan@Sun.COM 	    "reg", reg, 5));
575210923SEvan.Yan@Sun.COM }
575310923SEvan.Yan@Sun.COM 
575410923SEvan.Yan@Sun.COM static int
pcicfg_dump_assigned(dev_info_t * dip)575510923SEvan.Yan@Sun.COM pcicfg_dump_assigned(dev_info_t *dip)
575610923SEvan.Yan@Sun.COM {
575710923SEvan.Yan@Sun.COM 	pci_regspec_t		*reg;
575810923SEvan.Yan@Sun.COM 	int			length;
575910923SEvan.Yan@Sun.COM 	int			rcount;
576010923SEvan.Yan@Sun.COM 	int			i;
576110923SEvan.Yan@Sun.COM 
576210923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
576310923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&reg,
576410923SEvan.Yan@Sun.COM 	    &length) != DDI_PROP_SUCCESS) {
576510923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read assigned-addresses property\n");
576610923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
576710923SEvan.Yan@Sun.COM 	}
576810923SEvan.Yan@Sun.COM 
576910923SEvan.Yan@Sun.COM 	rcount = length / sizeof (pci_regspec_t);
577010923SEvan.Yan@Sun.COM 	for (i = 0; i < rcount; i++) {
577110923SEvan.Yan@Sun.COM 		DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n",
577210923SEvan.Yan@Sun.COM 		    reg[i].pci_size_low, reg[i].pci_phys_low,
577310923SEvan.Yan@Sun.COM 		    reg[i].pci_phys_mid, reg[i].pci_phys_hi);
577410923SEvan.Yan@Sun.COM 	}
577510923SEvan.Yan@Sun.COM 	/*
577610923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
577710923SEvan.Yan@Sun.COM 	 */
577810923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)reg, length);
577910923SEvan.Yan@Sun.COM 
578010923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
578110923SEvan.Yan@Sun.COM }
578210923SEvan.Yan@Sun.COM 
578310923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
578410923SEvan.Yan@Sun.COM static int
pcicfg_load_fcode(dev_info_t * dip,uint_t bus,uint_t device,uint_t func,uint16_t vendor_id,uint16_t device_id,uchar_t ** fcode_addr,int * fcode_size,int rom_paddr,int rom_size)578510923SEvan.Yan@Sun.COM pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func,
578610923SEvan.Yan@Sun.COM     uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr,
578710923SEvan.Yan@Sun.COM     int *fcode_size, int rom_paddr, int rom_size)
578810923SEvan.Yan@Sun.COM {
578910923SEvan.Yan@Sun.COM 	pci_regspec_t		p;
579010923SEvan.Yan@Sun.COM 	int			pci_data;
579110923SEvan.Yan@Sun.COM 	int			start_of_fcode;
579210923SEvan.Yan@Sun.COM 	int			image_length;
579310923SEvan.Yan@Sun.COM 	int			code_type;
579410923SEvan.Yan@Sun.COM 	ddi_acc_handle_t	h;
579510923SEvan.Yan@Sun.COM 	ddi_device_acc_attr_t	acc;
579610923SEvan.Yan@Sun.COM 	uint8_t			*addr;
579710923SEvan.Yan@Sun.COM 	int8_t			image_not_found, indicator;
579810923SEvan.Yan@Sun.COM 	uint16_t		vendor_id_img, device_id_img;
579910923SEvan.Yan@Sun.COM 	int16_t			rom_sig;
580010923SEvan.Yan@Sun.COM #ifdef DEBUG
580110923SEvan.Yan@Sun.COM 	int i;
580210923SEvan.Yan@Sun.COM #endif
580310923SEvan.Yan@Sun.COM 
580410923SEvan.Yan@Sun.COM 	DEBUG4("pcicfg_load_fcode() - "
580510923SEvan.Yan@Sun.COM 	    "bus %x device =%x func=%x rom_paddr=%lx\n",
580610923SEvan.Yan@Sun.COM 	    bus, device, func, rom_paddr);
580710923SEvan.Yan@Sun.COM 	DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n",
580810923SEvan.Yan@Sun.COM 	    vendor_id, device_id);
580910923SEvan.Yan@Sun.COM 
581010923SEvan.Yan@Sun.COM 	*fcode_size = 0;
581110923SEvan.Yan@Sun.COM 	*fcode_addr = NULL;
581210923SEvan.Yan@Sun.COM 
581310923SEvan.Yan@Sun.COM 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
581410923SEvan.Yan@Sun.COM 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
581510923SEvan.Yan@Sun.COM 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
581610923SEvan.Yan@Sun.COM 
581710923SEvan.Yan@Sun.COM 	p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device,
581810923SEvan.Yan@Sun.COM 	    func, PCI_CONF_ROM);
581910923SEvan.Yan@Sun.COM 
582010923SEvan.Yan@Sun.COM 	p.pci_phys_mid = 0;
582110923SEvan.Yan@Sun.COM 	p.pci_phys_low = 0;
582210923SEvan.Yan@Sun.COM 
582310923SEvan.Yan@Sun.COM 	p.pci_size_low = rom_size;
582410923SEvan.Yan@Sun.COM 	p.pci_size_hi = 0;
582510923SEvan.Yan@Sun.COM 
582610923SEvan.Yan@Sun.COM 	if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) {
582710923SEvan.Yan@Sun.COM 		DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low);
582810923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
582910923SEvan.Yan@Sun.COM 	}
583010923SEvan.Yan@Sun.COM 
583110923SEvan.Yan@Sun.COM 	/*
583210923SEvan.Yan@Sun.COM 	 * Walk the ROM to find the proper image for this device.
583310923SEvan.Yan@Sun.COM 	 */
583410923SEvan.Yan@Sun.COM 	image_not_found = 1;
583510923SEvan.Yan@Sun.COM 	while (image_not_found) {
583610923SEvan.Yan@Sun.COM 		DEBUG1("Expansion ROM maps to %lx\n", addr);
583710923SEvan.Yan@Sun.COM 
583810923SEvan.Yan@Sun.COM #ifdef DEBUG
583910923SEvan.Yan@Sun.COM 		if (pcicfg_dump_fcode) {
584010923SEvan.Yan@Sun.COM 			for (i = 0; i < 100; i++)
584110923SEvan.Yan@Sun.COM 				DEBUG2("ROM 0x%x --> 0x%x\n", i,
584210923SEvan.Yan@Sun.COM 				    ddi_get8(h, (uint8_t *)(addr + i)));
584310923SEvan.Yan@Sun.COM 		}
584410923SEvan.Yan@Sun.COM #endif
584510923SEvan.Yan@Sun.COM 
584610923SEvan.Yan@Sun.COM 		/*
584710923SEvan.Yan@Sun.COM 		 * Some device say they have an Expansion ROM, but do not, so
584810923SEvan.Yan@Sun.COM 		 * for non-21554 devices use peek so we don't panic due to
584910923SEvan.Yan@Sun.COM 		 * accessing non existent memory.
585010923SEvan.Yan@Sun.COM 		 */
585110923SEvan.Yan@Sun.COM 		if (pcicfg_indirect_map(dip) == DDI_SUCCESS) {
585210923SEvan.Yan@Sun.COM 			rom_sig = ddi_get16(h,
585310923SEvan.Yan@Sun.COM 			    (uint16_t *)(addr + PCI_ROM_SIGNATURE));
585410923SEvan.Yan@Sun.COM 		} else {
585510923SEvan.Yan@Sun.COM 			if (ddi_peek16(dip,
585610923SEvan.Yan@Sun.COM 			    (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) {
585710923SEvan.Yan@Sun.COM 				cmn_err(CE_WARN,
585810923SEvan.Yan@Sun.COM 				    "PCI Expansion ROM is not accessible");
585910923SEvan.Yan@Sun.COM 				pcicfg_unmap_phys(&h, &p);
586010923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
586110923SEvan.Yan@Sun.COM 			}
586210923SEvan.Yan@Sun.COM 		}
586310923SEvan.Yan@Sun.COM 
586410923SEvan.Yan@Sun.COM 		/*
586510923SEvan.Yan@Sun.COM 		 * Validate the ROM Signature.
586610923SEvan.Yan@Sun.COM 		 */
586710923SEvan.Yan@Sun.COM 		if ((uint16_t)rom_sig != 0xaa55) {
586810923SEvan.Yan@Sun.COM 			DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig);
586910923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &p);
587010923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
587110923SEvan.Yan@Sun.COM 		}
587210923SEvan.Yan@Sun.COM 
587310923SEvan.Yan@Sun.COM 		DEBUG0("Valid ROM Signature Found\n");
587410923SEvan.Yan@Sun.COM 
587510923SEvan.Yan@Sun.COM 		start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2));
587610923SEvan.Yan@Sun.COM 
587710923SEvan.Yan@Sun.COM 		pci_data =  ddi_get16(h,
587810923SEvan.Yan@Sun.COM 		    (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR));
587910923SEvan.Yan@Sun.COM 
588010923SEvan.Yan@Sun.COM 		DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data,
588110923SEvan.Yan@Sun.COM 		    addr);
588210923SEvan.Yan@Sun.COM 
588310923SEvan.Yan@Sun.COM 		/*
588410923SEvan.Yan@Sun.COM 		 * Validate the PCI Data Structure Signature.
588510923SEvan.Yan@Sun.COM 		 * 0x52494350 = "PCIR"
588610923SEvan.Yan@Sun.COM 		 */
588710923SEvan.Yan@Sun.COM 
588810923SEvan.Yan@Sun.COM 		if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) {
588910923SEvan.Yan@Sun.COM 			DEBUG0("Invalid PCI Data Structure Signature\n");
589010923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &p);
589110923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
589210923SEvan.Yan@Sun.COM 		}
589310923SEvan.Yan@Sun.COM 
589410923SEvan.Yan@Sun.COM 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) {
589510923SEvan.Yan@Sun.COM 			DEBUG0("Invalid PCI Data Structure Signature\n");
589610923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &p);
589710923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
589810923SEvan.Yan@Sun.COM 		}
589910923SEvan.Yan@Sun.COM 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) {
590010923SEvan.Yan@Sun.COM 			DEBUG0("Invalid PCI Data Structure Signature\n");
590110923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &p);
590210923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
590310923SEvan.Yan@Sun.COM 		}
590410923SEvan.Yan@Sun.COM 		if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) {
590510923SEvan.Yan@Sun.COM 			DEBUG0("Invalid PCI Data Structure Signature\n");
590610923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &p);
590710923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
590810923SEvan.Yan@Sun.COM 		}
590910923SEvan.Yan@Sun.COM 
591010923SEvan.Yan@Sun.COM 		/*
591110923SEvan.Yan@Sun.COM 		 * Is this image for this device?
591210923SEvan.Yan@Sun.COM 		 */
591310923SEvan.Yan@Sun.COM 		vendor_id_img = ddi_get16(h,
591410923SEvan.Yan@Sun.COM 		    (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID));
591510923SEvan.Yan@Sun.COM 		device_id_img = ddi_get16(h,
591610923SEvan.Yan@Sun.COM 		    (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID));
591710923SEvan.Yan@Sun.COM 
591810923SEvan.Yan@Sun.COM 		DEBUG2("This image is for vendor_id=%x device_id=%x\n",
591910923SEvan.Yan@Sun.COM 		    vendor_id_img, device_id_img);
592010923SEvan.Yan@Sun.COM 
592110923SEvan.Yan@Sun.COM 		code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE);
592210923SEvan.Yan@Sun.COM 
592310923SEvan.Yan@Sun.COM 		switch (code_type) {
592410923SEvan.Yan@Sun.COM 		case PCI_PDS_CODE_TYPE_PCAT:
592510923SEvan.Yan@Sun.COM 			DEBUG0("ROM is of x86/PC-AT Type\n");
592610923SEvan.Yan@Sun.COM 			break;
592710923SEvan.Yan@Sun.COM 		case PCI_PDS_CODE_TYPE_OPEN_FW:
592810923SEvan.Yan@Sun.COM 			DEBUG0("ROM is of Open Firmware Type\n");
592910923SEvan.Yan@Sun.COM 			break;
593010923SEvan.Yan@Sun.COM 		default:
593110923SEvan.Yan@Sun.COM 			DEBUG1("ROM is of Unknown Type 0x%x\n", code_type);
593210923SEvan.Yan@Sun.COM 			break;
593310923SEvan.Yan@Sun.COM 		}
593410923SEvan.Yan@Sun.COM 
593510923SEvan.Yan@Sun.COM 		if ((vendor_id_img != vendor_id) ||
593610923SEvan.Yan@Sun.COM 		    (device_id_img != device_id) ||
593710923SEvan.Yan@Sun.COM 		    (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) {
593810923SEvan.Yan@Sun.COM 			DEBUG0("Firmware Image is not for this device..."
593910923SEvan.Yan@Sun.COM 			    "goto next image\n");
594010923SEvan.Yan@Sun.COM 			/*
594110923SEvan.Yan@Sun.COM 			 * Read indicator byte to see if there is another
594210923SEvan.Yan@Sun.COM 			 * image in the ROM
594310923SEvan.Yan@Sun.COM 			 */
594410923SEvan.Yan@Sun.COM 			indicator = ddi_get8(h,
594510923SEvan.Yan@Sun.COM 			    (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR));
594610923SEvan.Yan@Sun.COM 
594710923SEvan.Yan@Sun.COM 			if (indicator != 1) {
594810923SEvan.Yan@Sun.COM 				/*
594910923SEvan.Yan@Sun.COM 				 * There is another image in the ROM.
595010923SEvan.Yan@Sun.COM 				 */
595110923SEvan.Yan@Sun.COM 				image_length = ddi_get16(h,  (uint16_t *)(addr +
595210923SEvan.Yan@Sun.COM 				    pci_data + PCI_PDS_IMAGE_LENGTH)) * 512;
595310923SEvan.Yan@Sun.COM 
595410923SEvan.Yan@Sun.COM 				addr += image_length;
595510923SEvan.Yan@Sun.COM 			} else {
595610923SEvan.Yan@Sun.COM 				/*
595710923SEvan.Yan@Sun.COM 				 * There are no more images.
595810923SEvan.Yan@Sun.COM 				 */
595910923SEvan.Yan@Sun.COM 				DEBUG0("There are no more images in the ROM\n");
596010923SEvan.Yan@Sun.COM 				pcicfg_unmap_phys(&h, &p);
596110923SEvan.Yan@Sun.COM 
596210923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
596310923SEvan.Yan@Sun.COM 			}
596410923SEvan.Yan@Sun.COM 		} else {
596510923SEvan.Yan@Sun.COM 			DEBUG0("Correct image was found\n");
596610923SEvan.Yan@Sun.COM 			image_not_found = 0;  /* Image was found */
596710923SEvan.Yan@Sun.COM 		}
596810923SEvan.Yan@Sun.COM 	}
596910923SEvan.Yan@Sun.COM 
597010923SEvan.Yan@Sun.COM 	*fcode_size =  (ddi_get8(h, addr + start_of_fcode + 4) << 24) |
597110923SEvan.Yan@Sun.COM 	    (ddi_get8(h, addr + start_of_fcode + 5) << 16) |
597210923SEvan.Yan@Sun.COM 	    (ddi_get8(h, addr + start_of_fcode + 6) << 8) |
597310923SEvan.Yan@Sun.COM 	    (ddi_get8(h, addr + start_of_fcode + 7));
597410923SEvan.Yan@Sun.COM 
597510923SEvan.Yan@Sun.COM 	DEBUG1("Fcode Size %x\n", *fcode_size);
597610923SEvan.Yan@Sun.COM 
597710923SEvan.Yan@Sun.COM 	/*
597810923SEvan.Yan@Sun.COM 	 * Allocate page aligned buffer space
597910923SEvan.Yan@Sun.COM 	 */
598010923SEvan.Yan@Sun.COM 	*fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP);
598110923SEvan.Yan@Sun.COM 
598210923SEvan.Yan@Sun.COM 	if (*fcode_addr == NULL) {
598310923SEvan.Yan@Sun.COM 		DEBUG0("kmem_zalloc returned NULL\n");
598410923SEvan.Yan@Sun.COM 		pcicfg_unmap_phys(&h, &p);
598510923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
598610923SEvan.Yan@Sun.COM 	}
598710923SEvan.Yan@Sun.COM 
598810923SEvan.Yan@Sun.COM 	DEBUG1("Fcode Addr %lx\n", *fcode_addr);
598910923SEvan.Yan@Sun.COM 
599010923SEvan.Yan@Sun.COM 	ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size,
599110923SEvan.Yan@Sun.COM 	    DDI_DEV_AUTOINCR);
599210923SEvan.Yan@Sun.COM 
599310923SEvan.Yan@Sun.COM 	pcicfg_unmap_phys(&h, &p);
599410923SEvan.Yan@Sun.COM 
599510923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
599610923SEvan.Yan@Sun.COM }
599710923SEvan.Yan@Sun.COM 
599810923SEvan.Yan@Sun.COM static int
pcicfg_fcode_assign_bars(ddi_acc_handle_t h,dev_info_t * dip,uint_t bus,uint_t device,uint_t func,int32_t fc_request,pci_regspec_t * rom_regspec)599910923SEvan.Yan@Sun.COM pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus,
600010923SEvan.Yan@Sun.COM     uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec)
600110923SEvan.Yan@Sun.COM {
600210923SEvan.Yan@Sun.COM 	/*
600310923SEvan.Yan@Sun.COM 	 * Assign values to all BARs so that it is safe to turn on the
600410923SEvan.Yan@Sun.COM 	 * device for accessing the fcode on the PROM. On successful
600510923SEvan.Yan@Sun.COM 	 * exit from this function, "assigned-addresses" are created
600610923SEvan.Yan@Sun.COM 	 * for all BARs and ROM BAR is enabled. Also, rom_regspec is
600710923SEvan.Yan@Sun.COM 	 * filled with the values that can be used to free up this
600810923SEvan.Yan@Sun.COM 	 * resource later.
600910923SEvan.Yan@Sun.COM 	 */
601010923SEvan.Yan@Sun.COM 	uint32_t request, hiword, size;
601110923SEvan.Yan@Sun.COM 	pci_regspec_t phys_spec;
601210923SEvan.Yan@Sun.COM 	ndi_ra_request_t req;
601310923SEvan.Yan@Sun.COM 	uint64_t mem_answer, mem_alen;
601410923SEvan.Yan@Sun.COM 	int i;
601510923SEvan.Yan@Sun.COM 
601610923SEvan.Yan@Sun.COM 	DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name);
601710923SEvan.Yan@Sun.COM 
601810923SEvan.Yan@Sun.COM 	/*
601910923SEvan.Yan@Sun.COM 	 * Process the BARs.
602010923SEvan.Yan@Sun.COM 	 */
602110923SEvan.Yan@Sun.COM 	for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) {
602210923SEvan.Yan@Sun.COM 		pci_config_put32(h, i, 0xffffffff);
602310923SEvan.Yan@Sun.COM 		request = pci_config_get32(h, i);
602410923SEvan.Yan@Sun.COM 		/*
602510923SEvan.Yan@Sun.COM 		 * Check if implemented
602610923SEvan.Yan@Sun.COM 		 */
602710923SEvan.Yan@Sun.COM 		if (request == 0) {
602810923SEvan.Yan@Sun.COM 			DEBUG1("pcicfg_fcode_assign_bars :"
602910923SEvan.Yan@Sun.COM 			    "BASE register [0x%x] asks for 0(32)\n", i);
603010923SEvan.Yan@Sun.COM 			i += 4;
603110923SEvan.Yan@Sun.COM 			continue;
603210923SEvan.Yan@Sun.COM 		}
603310923SEvan.Yan@Sun.COM 		/*
603410923SEvan.Yan@Sun.COM 		 * Build the phys_spec for this BAR
603510923SEvan.Yan@Sun.COM 		 */
603610923SEvan.Yan@Sun.COM 		hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i);
603710923SEvan.Yan@Sun.COM 		size = (~(PCI_BASE_M_ADDR_M & request)) + 1;
603810923SEvan.Yan@Sun.COM 
603910923SEvan.Yan@Sun.COM 		DEBUG3("pcicfg_fcode_assign_bars :"
604010923SEvan.Yan@Sun.COM 		    "BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
604110923SEvan.Yan@Sun.COM 		    i, request, size);
604210923SEvan.Yan@Sun.COM 
604310923SEvan.Yan@Sun.COM 		if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) {
604410923SEvan.Yan@Sun.COM 			if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) {
604510923SEvan.Yan@Sun.COM 				hiword |= PCI_ADDR_MEM32;
604610923SEvan.Yan@Sun.COM 			} else if ((PCI_BASE_TYPE_M & request)
604710923SEvan.Yan@Sun.COM 			    == PCI_BASE_TYPE_ALL) {
604810923SEvan.Yan@Sun.COM 				hiword |= PCI_ADDR_MEM64;
604910923SEvan.Yan@Sun.COM 			}
605010923SEvan.Yan@Sun.COM 			if (request & PCI_BASE_PREF_M)
605110923SEvan.Yan@Sun.COM 				hiword |= PCI_REG_PF_M;
605210923SEvan.Yan@Sun.COM 		} else {
605310923SEvan.Yan@Sun.COM 			hiword |= PCI_ADDR_IO;
605410923SEvan.Yan@Sun.COM 		}
605510923SEvan.Yan@Sun.COM 		phys_spec.pci_phys_hi = hiword;
605610923SEvan.Yan@Sun.COM 		phys_spec.pci_phys_mid = 0;
605710923SEvan.Yan@Sun.COM 		phys_spec.pci_phys_low = 0;
605810923SEvan.Yan@Sun.COM 		phys_spec.pci_size_hi = 0;
605910923SEvan.Yan@Sun.COM 		phys_spec.pci_size_low = size;
606010923SEvan.Yan@Sun.COM 
606110923SEvan.Yan@Sun.COM 		/*
606210923SEvan.Yan@Sun.COM 		 * The following function
606310923SEvan.Yan@Sun.COM 		 * - allocates address space
606410923SEvan.Yan@Sun.COM 		 * - programs the BAR
606510923SEvan.Yan@Sun.COM 		 * - adds an "assigned-addresses" property
606610923SEvan.Yan@Sun.COM 		 */
606710923SEvan.Yan@Sun.COM 		if (pcicfg_alloc_resource(dip, phys_spec)) {
606810923SEvan.Yan@Sun.COM 			cmn_err(CE_WARN, "failed to allocate %d bytes"
606910923SEvan.Yan@Sun.COM 			    " for dev %s BASE register [0x%x]\n",
607010923SEvan.Yan@Sun.COM 			    size, DEVI(dip)->devi_name, i);
607110923SEvan.Yan@Sun.COM 			goto failure;
607210923SEvan.Yan@Sun.COM 		}
607310923SEvan.Yan@Sun.COM 		if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
607410923SEvan.Yan@Sun.COM 			/*
607510923SEvan.Yan@Sun.COM 			 * 64 bit, should be in memory space.
607610923SEvan.Yan@Sun.COM 			 */
607710923SEvan.Yan@Sun.COM 			i += 8;
607810923SEvan.Yan@Sun.COM 		} else {
607910923SEvan.Yan@Sun.COM 			/*
608010923SEvan.Yan@Sun.COM 			 * 32 bit, either memory or I/O space.
608110923SEvan.Yan@Sun.COM 			 */
608210923SEvan.Yan@Sun.COM 			i += 4;
608310923SEvan.Yan@Sun.COM 		}
608410923SEvan.Yan@Sun.COM 	}
608510923SEvan.Yan@Sun.COM 
608610923SEvan.Yan@Sun.COM 	/*
608710923SEvan.Yan@Sun.COM 	 * Handle ROM BAR. We do not use the common
608810923SEvan.Yan@Sun.COM 	 * resource allocator function because we need to
608910923SEvan.Yan@Sun.COM 	 * return reg spec to the caller.
609010923SEvan.Yan@Sun.COM 	 */
609110923SEvan.Yan@Sun.COM 	size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1;
609210923SEvan.Yan@Sun.COM 
609310923SEvan.Yan@Sun.COM 	DEBUG3("BASE register [0x%x] asks for "
609410923SEvan.Yan@Sun.COM 	    "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size);
609510923SEvan.Yan@Sun.COM 
609610923SEvan.Yan@Sun.COM 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
609710923SEvan.Yan@Sun.COM 
609810923SEvan.Yan@Sun.COM 	req.ra_boundbase = 0;
609910923SEvan.Yan@Sun.COM 	req.ra_boundlen = PCICFG_4GIG_LIMIT;
610010923SEvan.Yan@Sun.COM 	req.ra_len = size;
6101*12765SScott.Carter@Oracle.COM 	req.ra_flags = (NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED);
610210923SEvan.Yan@Sun.COM 
610310923SEvan.Yan@Sun.COM 	if (ndi_ra_alloc(ddi_get_parent(dip),
610410923SEvan.Yan@Sun.COM 	    &req, &mem_answer, &mem_alen,
610510923SEvan.Yan@Sun.COM 	    NDI_RA_TYPE_MEM, NDI_RA_PASS)) {
610610923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN, "failed to allocate %d bytes"
610710923SEvan.Yan@Sun.COM 		    " for dev %s ROM BASE register\n",
610810923SEvan.Yan@Sun.COM 		    size, DEVI(dip)->devi_name);
610910923SEvan.Yan@Sun.COM 		goto failure;
611010923SEvan.Yan@Sun.COM 	}
611110923SEvan.Yan@Sun.COM 
611210923SEvan.Yan@Sun.COM 	DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
611310923SEvan.Yan@Sun.COM 	    PCICFG_HIADDR(mem_answer),
611410923SEvan.Yan@Sun.COM 	    PCICFG_LOADDR(mem_answer), mem_alen);
611510923SEvan.Yan@Sun.COM 
611610923SEvan.Yan@Sun.COM 	/*
611710923SEvan.Yan@Sun.COM 	 * Assign address space and enable ROM.
611810923SEvan.Yan@Sun.COM 	 */
611910923SEvan.Yan@Sun.COM 	pci_config_put32(h, PCI_CONF_ROM,
612010923SEvan.Yan@Sun.COM 	    PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE);
612110923SEvan.Yan@Sun.COM 
612210923SEvan.Yan@Sun.COM 	/*
612310923SEvan.Yan@Sun.COM 	 * Add resource to assigned-addresses.
612410923SEvan.Yan@Sun.COM 	 */
612510923SEvan.Yan@Sun.COM 	phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \
612610923SEvan.Yan@Sun.COM 	    PCI_CONF_ROM) | PCI_ADDR_MEM32;
612710923SEvan.Yan@Sun.COM 	if (fc_request & PCI_BASE_PREF_M)
612810923SEvan.Yan@Sun.COM 		phys_spec.pci_phys_hi |= PCI_REG_PF_M;
612910923SEvan.Yan@Sun.COM 	phys_spec.pci_phys_mid = 0;
613010923SEvan.Yan@Sun.COM 	phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer);
613110923SEvan.Yan@Sun.COM 	phys_spec.pci_size_hi = 0;
613210923SEvan.Yan@Sun.COM 	phys_spec.pci_size_low = size;
613310923SEvan.Yan@Sun.COM 
613410923SEvan.Yan@Sun.COM 	if (pcicfg_update_assigned_prop(dip, &phys_spec)
613510923SEvan.Yan@Sun.COM 	    != PCICFG_SUCCESS) {
613610923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN, "failed to update"
613710923SEvan.Yan@Sun.COM 		    " assigned-address property for dev %s\n",
613810923SEvan.Yan@Sun.COM 		    DEVI(dip)->devi_name);
613910923SEvan.Yan@Sun.COM 		goto failure;
614010923SEvan.Yan@Sun.COM 	}
614110923SEvan.Yan@Sun.COM 	/*
614210923SEvan.Yan@Sun.COM 	 * Copy out the reg spec.
614310923SEvan.Yan@Sun.COM 	 */
614410923SEvan.Yan@Sun.COM 	*rom_regspec = phys_spec;
614510923SEvan.Yan@Sun.COM 
614610923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
614710923SEvan.Yan@Sun.COM 
614810923SEvan.Yan@Sun.COM failure:
614910923SEvan.Yan@Sun.COM 	/*
615010923SEvan.Yan@Sun.COM 	 * We came in with no "assigned-addresses".
615110923SEvan.Yan@Sun.COM 	 * Free up the resources we may have allocated.
615210923SEvan.Yan@Sun.COM 	 */
615310923SEvan.Yan@Sun.COM 	(void) pcicfg_free_device_resources(dip, 0);
615410923SEvan.Yan@Sun.COM 
615510923SEvan.Yan@Sun.COM 	return (PCICFG_FAILURE);
615610923SEvan.Yan@Sun.COM }
615710923SEvan.Yan@Sun.COM 
615810923SEvan.Yan@Sun.COM #endif /* PCICFG_INTERPRET_FCODE */
615910923SEvan.Yan@Sun.COM 
616010923SEvan.Yan@Sun.COM static int
pcicfg_free_all_resources(dev_info_t * dip)616110923SEvan.Yan@Sun.COM pcicfg_free_all_resources(dev_info_t *dip)
616210923SEvan.Yan@Sun.COM {
616310923SEvan.Yan@Sun.COM 	pci_regspec_t		*assigned;
616410923SEvan.Yan@Sun.COM 	int			assigned_len;
616510923SEvan.Yan@Sun.COM 	int			acount;
616610923SEvan.Yan@Sun.COM 	int			i;
616710923SEvan.Yan@Sun.COM 
616810923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
616910923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
617010923SEvan.Yan@Sun.COM 	    &assigned_len) != DDI_PROP_SUCCESS) {
617110923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read assigned-addresses property\n");
617210923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
617310923SEvan.Yan@Sun.COM 	}
617410923SEvan.Yan@Sun.COM 
617510923SEvan.Yan@Sun.COM 	acount = assigned_len / sizeof (pci_regspec_t);
617610923SEvan.Yan@Sun.COM 
617710923SEvan.Yan@Sun.COM 	for (i = 0; i < acount; i++) {
617810923SEvan.Yan@Sun.COM 		if (pcicfg_free_resource(dip, assigned[i], 0)) {
617910923SEvan.Yan@Sun.COM 			/*
618010923SEvan.Yan@Sun.COM 			 * Dont forget to free mem from ddi_getlongprop
618110923SEvan.Yan@Sun.COM 			 */
618210923SEvan.Yan@Sun.COM 			kmem_free((caddr_t)assigned, assigned_len);
618310923SEvan.Yan@Sun.COM 			return (PCICFG_FAILURE);
618410923SEvan.Yan@Sun.COM 		}
618510923SEvan.Yan@Sun.COM 	}
618610923SEvan.Yan@Sun.COM 
618710923SEvan.Yan@Sun.COM 	/*
618810923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
618910923SEvan.Yan@Sun.COM 	 */
619010923SEvan.Yan@Sun.COM 	if (assigned_len)
619110923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)assigned, assigned_len);
619210923SEvan.Yan@Sun.COM 
619310923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
619410923SEvan.Yan@Sun.COM }
619510923SEvan.Yan@Sun.COM static int
pcicfg_alloc_new_resources(dev_info_t * dip)619610923SEvan.Yan@Sun.COM pcicfg_alloc_new_resources(dev_info_t *dip)
619710923SEvan.Yan@Sun.COM {
619810923SEvan.Yan@Sun.COM 	pci_regspec_t		*assigned, *reg;
619910923SEvan.Yan@Sun.COM 	int			assigned_len, reg_len;
620010923SEvan.Yan@Sun.COM 	int			acount, rcount;
620110923SEvan.Yan@Sun.COM 	int			i, j, alloc_size;
620210923SEvan.Yan@Sun.COM 	boolean_t		alloc;
620310923SEvan.Yan@Sun.COM 
620410923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
620510923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg,
620610923SEvan.Yan@Sun.COM 	    &reg_len) != DDI_PROP_SUCCESS) {
620710923SEvan.Yan@Sun.COM 		DEBUG0("Failed to read reg property\n");
620810923SEvan.Yan@Sun.COM 		return (PCICFG_FAILURE);
620910923SEvan.Yan@Sun.COM 	}
621010923SEvan.Yan@Sun.COM 	rcount = reg_len / sizeof (pci_regspec_t);
621110923SEvan.Yan@Sun.COM 
621210923SEvan.Yan@Sun.COM 	DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n",
621310923SEvan.Yan@Sun.COM 	    reg_len, rcount);
621410923SEvan.Yan@Sun.COM 
621510923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
621610923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
621710923SEvan.Yan@Sun.COM 	    &assigned_len) != DDI_PROP_SUCCESS) {
621810923SEvan.Yan@Sun.COM 		acount = 0;
621910923SEvan.Yan@Sun.COM 	} else {
622010923SEvan.Yan@Sun.COM 		acount = assigned_len / sizeof (pci_regspec_t);
622110923SEvan.Yan@Sun.COM 	}
622210923SEvan.Yan@Sun.COM 
622310923SEvan.Yan@Sun.COM 	DEBUG1("assigned-addresses property len=%x\n", acount);
622410923SEvan.Yan@Sun.COM 
622510923SEvan.Yan@Sun.COM 	/*
622610923SEvan.Yan@Sun.COM 	 * For each address described by reg, search for it in the
622710923SEvan.Yan@Sun.COM 	 * assigned-addresses property. If it does not exist, allocate
622810923SEvan.Yan@Sun.COM 	 * resources for it. If it does exist, check the size in both.
622910923SEvan.Yan@Sun.COM 	 * The size needs to be bigger of the two.
623010923SEvan.Yan@Sun.COM 	 */
623110923SEvan.Yan@Sun.COM 	for (i = 1; i < rcount; i++) {
623210923SEvan.Yan@Sun.COM 		alloc = B_TRUE;
623310923SEvan.Yan@Sun.COM 		alloc_size = reg[i].pci_size_low;
623410923SEvan.Yan@Sun.COM 		for (j = 0; j < acount; j++) {
623510923SEvan.Yan@Sun.COM 			if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) {
623610923SEvan.Yan@Sun.COM 				/*
623710923SEvan.Yan@Sun.COM 				 * There is an exact match. Check size.
623810923SEvan.Yan@Sun.COM 				 */
623910923SEvan.Yan@Sun.COM 				DEBUG1("pcicfg_alloc_new_resources "
624010923SEvan.Yan@Sun.COM 				    "- %x - MATCH\n",
624110923SEvan.Yan@Sun.COM 				    reg[i].pci_phys_hi);
624210923SEvan.Yan@Sun.COM 
624310923SEvan.Yan@Sun.COM 				if (reg[i].pci_size_low >
624410923SEvan.Yan@Sun.COM 				    assigned[j].pci_size_low) {
624510923SEvan.Yan@Sun.COM 					/*
624610923SEvan.Yan@Sun.COM 					 * Fcode wants more.
624710923SEvan.Yan@Sun.COM 					 */
624810923SEvan.Yan@Sun.COM 					DEBUG3("pcicfg_alloc_new_resources"
624910923SEvan.Yan@Sun.COM 					    " - %x - RESIZE"
625010923SEvan.Yan@Sun.COM 					    " assigned 0x%x reg 0x%x\n",
625110923SEvan.Yan@Sun.COM 					    assigned[j].pci_phys_hi,
625210923SEvan.Yan@Sun.COM 					    assigned[j].pci_size_low,
625310923SEvan.Yan@Sun.COM 					    reg[i].pci_size_low);
625410923SEvan.Yan@Sun.COM 
625510923SEvan.Yan@Sun.COM 					/*
625610923SEvan.Yan@Sun.COM 					 * Free the old resource.
625710923SEvan.Yan@Sun.COM 					 */
625810923SEvan.Yan@Sun.COM 					(void) pcicfg_free_resource(dip,
625910923SEvan.Yan@Sun.COM 					    assigned[j], 0);
626010923SEvan.Yan@Sun.COM 				} else {
626110923SEvan.Yan@Sun.COM 					DEBUG3("pcicfg_alloc_new_resources"
626210923SEvan.Yan@Sun.COM 					    " - %x - ENOUGH"
626310923SEvan.Yan@Sun.COM 					    " assigned 0x%x reg 0x%x\n",
626410923SEvan.Yan@Sun.COM 					    assigned[j].pci_phys_hi,
626510923SEvan.Yan@Sun.COM 					    assigned[j].pci_size_low,
626610923SEvan.Yan@Sun.COM 					    reg[i].pci_size_low);
626710923SEvan.Yan@Sun.COM 
626810923SEvan.Yan@Sun.COM 					alloc = B_FALSE;
626910923SEvan.Yan@Sun.COM 				}
627010923SEvan.Yan@Sun.COM 				break;
627110923SEvan.Yan@Sun.COM 			}
627210923SEvan.Yan@Sun.COM 			/*
627310923SEvan.Yan@Sun.COM 			 * Fcode may have set one or more of the
627410923SEvan.Yan@Sun.COM 			 * NPT bits in phys.hi.
627510923SEvan.Yan@Sun.COM 			 */
627610923SEvan.Yan@Sun.COM 			if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) ==
627710923SEvan.Yan@Sun.COM 			    PCI_REG_BDFR_G(reg[i].pci_phys_hi)) {
627810923SEvan.Yan@Sun.COM 
627910923SEvan.Yan@Sun.COM 				DEBUG2("pcicfg_alloc_new_resources "
628010923SEvan.Yan@Sun.COM 				    "- PARTIAL MATCH assigned 0x%x "
628110923SEvan.Yan@Sun.COM 				    "reg 0x%x\n", assigned[j].pci_phys_hi,
628210923SEvan.Yan@Sun.COM 				    reg[i].pci_phys_hi);
628310923SEvan.Yan@Sun.COM 				/*
628410923SEvan.Yan@Sun.COM 				 * Changing the SS bits is an error
628510923SEvan.Yan@Sun.COM 				 */
628610923SEvan.Yan@Sun.COM 				if (PCI_REG_ADDR_G(
628710923SEvan.Yan@Sun.COM 				    assigned[j].pci_phys_hi) !=
628810923SEvan.Yan@Sun.COM 				    PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
628910923SEvan.Yan@Sun.COM 
629010923SEvan.Yan@Sun.COM 					DEBUG2("Fcode changing"
629110923SEvan.Yan@Sun.COM 					    " SS bits of - 0x%x -"
629210923SEvan.Yan@Sun.COM 					    " on %s\n", reg[i].pci_phys_hi,
629310923SEvan.Yan@Sun.COM 					    DEVI(dip)->devi_name);
629410923SEvan.Yan@Sun.COM 
629510923SEvan.Yan@Sun.COM 				}
629610923SEvan.Yan@Sun.COM 
629710923SEvan.Yan@Sun.COM 
629810923SEvan.Yan@Sun.COM 				/*
629910923SEvan.Yan@Sun.COM 				 * We are going to allocate new resource.
630010923SEvan.Yan@Sun.COM 				 * Free the old resource. Again, adjust
630110923SEvan.Yan@Sun.COM 				 * the size to be safe.
630210923SEvan.Yan@Sun.COM 				 */
630310923SEvan.Yan@Sun.COM 				(void) pcicfg_free_resource(dip,
630410923SEvan.Yan@Sun.COM 				    assigned[j], 0);
630510923SEvan.Yan@Sun.COM 
630610923SEvan.Yan@Sun.COM 				alloc_size = MAX(reg[i].pci_size_low,
630710923SEvan.Yan@Sun.COM 				    assigned[j].pci_size_low);
630810923SEvan.Yan@Sun.COM 
630910923SEvan.Yan@Sun.COM 				break;
631010923SEvan.Yan@Sun.COM 			}
631110923SEvan.Yan@Sun.COM 		}
631210923SEvan.Yan@Sun.COM 		/*
631310923SEvan.Yan@Sun.COM 		 * We are allocating resources for one of three reasons -
631410923SEvan.Yan@Sun.COM 		 * - Fcode wants a larger address space
631510923SEvan.Yan@Sun.COM 		 * - Fcode has set changed/set n, p, t bits.
631610923SEvan.Yan@Sun.COM 		 * - It is a new "reg", it should be only ROM bar, but
631710923SEvan.Yan@Sun.COM 		 *   we don't do the checking.
631810923SEvan.Yan@Sun.COM 		 */
631910923SEvan.Yan@Sun.COM 		if (alloc == B_TRUE) {
632010923SEvan.Yan@Sun.COM 			DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n",
632110923SEvan.Yan@Sun.COM 			    reg[i].pci_phys_hi);
632210923SEvan.Yan@Sun.COM 
632310923SEvan.Yan@Sun.COM 			reg[i].pci_size_low = alloc_size;
632410923SEvan.Yan@Sun.COM 			if (pcicfg_alloc_resource(dip, reg[i])) {
632510923SEvan.Yan@Sun.COM 				/*
632610923SEvan.Yan@Sun.COM 				 * Dont forget to free mem from
632710923SEvan.Yan@Sun.COM 				 * ddi_getlongprop
632810923SEvan.Yan@Sun.COM 				 */
632910923SEvan.Yan@Sun.COM 				if (acount != 0)
633010923SEvan.Yan@Sun.COM 					kmem_free((caddr_t)assigned,
633110923SEvan.Yan@Sun.COM 					    assigned_len);
633210923SEvan.Yan@Sun.COM 				kmem_free((caddr_t)reg, reg_len);
633310923SEvan.Yan@Sun.COM 				return (PCICFG_FAILURE);
633410923SEvan.Yan@Sun.COM 			}
633510923SEvan.Yan@Sun.COM 		}
633610923SEvan.Yan@Sun.COM 	}
633710923SEvan.Yan@Sun.COM 
633810923SEvan.Yan@Sun.COM 	/*
633910923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
634010923SEvan.Yan@Sun.COM 	 */
634110923SEvan.Yan@Sun.COM 	if (acount != 0)
634210923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)assigned, assigned_len);
634310923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)reg, reg_len);
634410923SEvan.Yan@Sun.COM 
634510923SEvan.Yan@Sun.COM 	return (PCICFG_SUCCESS);
634610923SEvan.Yan@Sun.COM }
634710923SEvan.Yan@Sun.COM 
634810923SEvan.Yan@Sun.COM static int
pcicfg_alloc_resource(dev_info_t * dip,pci_regspec_t phys_spec)634910923SEvan.Yan@Sun.COM pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
635010923SEvan.Yan@Sun.COM {
635110923SEvan.Yan@Sun.COM 	uint64_t answer;
635210923SEvan.Yan@Sun.COM 	uint64_t alen;
635310923SEvan.Yan@Sun.COM 	int offset;
635410923SEvan.Yan@Sun.COM 	pci_regspec_t config;
635510923SEvan.Yan@Sun.COM 	caddr_t virt, v;
635610923SEvan.Yan@Sun.COM 	ddi_device_acc_attr_t acc;
635710923SEvan.Yan@Sun.COM 	ddi_acc_handle_t h;
635810923SEvan.Yan@Sun.COM 	ndi_ra_request_t request;
635910923SEvan.Yan@Sun.COM 	pci_regspec_t *assigned;
636010923SEvan.Yan@Sun.COM 	int assigned_len, entries, i;
636110923SEvan.Yan@Sun.COM 
636210923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
636310923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
636410923SEvan.Yan@Sun.COM 	    &assigned_len) == DDI_PROP_SUCCESS) {
636510923SEvan.Yan@Sun.COM 		DEBUG0("pcicfg_alloc_resource - "
636610923SEvan.Yan@Sun.COM 		    "searching assigned-addresses\n");
636710923SEvan.Yan@Sun.COM 
636810923SEvan.Yan@Sun.COM 		entries = assigned_len / (sizeof (pci_regspec_t));
636910923SEvan.Yan@Sun.COM 
637010923SEvan.Yan@Sun.COM 		/*
637110923SEvan.Yan@Sun.COM 		 * Walk through the assigned-addresses entries. If there is
637210923SEvan.Yan@Sun.COM 		 * a match, there is no need to allocate the resource.
637310923SEvan.Yan@Sun.COM 		 */
637410923SEvan.Yan@Sun.COM 		for (i = 0; i < entries; i++) {
637510923SEvan.Yan@Sun.COM 			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
637610923SEvan.Yan@Sun.COM 				DEBUG1("pcicfg_alloc_resource - MATCH %x\n",
637710923SEvan.Yan@Sun.COM 				    assigned[i].pci_phys_hi);
637810923SEvan.Yan@Sun.COM 				kmem_free(assigned, assigned_len);
637910923SEvan.Yan@Sun.COM 				return (0);
638010923SEvan.Yan@Sun.COM 			}
638110923SEvan.Yan@Sun.COM 		}
638210923SEvan.Yan@Sun.COM 		kmem_free(assigned, assigned_len);
638310923SEvan.Yan@Sun.COM 	}
638410923SEvan.Yan@Sun.COM 
638510923SEvan.Yan@Sun.COM 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
638610923SEvan.Yan@Sun.COM 
638710923SEvan.Yan@Sun.COM 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
638810923SEvan.Yan@Sun.COM 	config.pci_phys_hi &= ~PCI_REG_REG_M;
638910923SEvan.Yan@Sun.COM 	config.pci_phys_mid = config.pci_phys_low = 0;
639010923SEvan.Yan@Sun.COM 	config.pci_size_hi = config.pci_size_low = 0;
639110923SEvan.Yan@Sun.COM 
639210923SEvan.Yan@Sun.COM 	/*
639310923SEvan.Yan@Sun.COM 	 * Map in configuration space (temporarily)
639410923SEvan.Yan@Sun.COM 	 */
639510923SEvan.Yan@Sun.COM 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
639610923SEvan.Yan@Sun.COM 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
639710923SEvan.Yan@Sun.COM 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
639810923SEvan.Yan@Sun.COM 
639910923SEvan.Yan@Sun.COM 	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
640010923SEvan.Yan@Sun.COM 		DEBUG0("Can not map in config space\n");
640110923SEvan.Yan@Sun.COM 		return (1);
640210923SEvan.Yan@Sun.COM 	}
640310923SEvan.Yan@Sun.COM 
6404*12765SScott.Carter@Oracle.COM 	request.ra_flags = NDI_RA_ALIGN_SIZE;
640510923SEvan.Yan@Sun.COM 	request.ra_boundbase = 0;
640610923SEvan.Yan@Sun.COM 	request.ra_boundlen = PCICFG_4GIG_LIMIT;
640710923SEvan.Yan@Sun.COM 	/*
640810923SEvan.Yan@Sun.COM 	 * Use size stored in phys_spec parameter.
640910923SEvan.Yan@Sun.COM 	 */
641010923SEvan.Yan@Sun.COM 	request.ra_len = phys_spec.pci_size_low;
641110923SEvan.Yan@Sun.COM 
641210923SEvan.Yan@Sun.COM 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
641310923SEvan.Yan@Sun.COM 
641410923SEvan.Yan@Sun.COM 	v = virt + offset;
641510923SEvan.Yan@Sun.COM 
641610923SEvan.Yan@Sun.COM 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
641710923SEvan.Yan@Sun.COM 
6418*12765SScott.Carter@Oracle.COM 		request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
641910923SEvan.Yan@Sun.COM 
642010923SEvan.Yan@Sun.COM 		/* allocate memory space from the allocator */
642110923SEvan.Yan@Sun.COM 
642210923SEvan.Yan@Sun.COM 		if (ndi_ra_alloc(ddi_get_parent(dip),
642310923SEvan.Yan@Sun.COM 		    &request, &answer, &alen,
642410923SEvan.Yan@Sun.COM 		    NDI_RA_TYPE_MEM, NDI_RA_PASS)
642510923SEvan.Yan@Sun.COM 		    != NDI_SUCCESS) {
642610923SEvan.Yan@Sun.COM 			DEBUG0("(ROM)Failed to allocate 32b mem");
642710923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &config);
642810923SEvan.Yan@Sun.COM 			return (1);
642910923SEvan.Yan@Sun.COM 		}
643010923SEvan.Yan@Sun.COM 		DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
643110923SEvan.Yan@Sun.COM 		    PCICFG_HIADDR(answer),
643210923SEvan.Yan@Sun.COM 		    PCICFG_LOADDR(answer),
643310923SEvan.Yan@Sun.COM 		    alen);
643410923SEvan.Yan@Sun.COM 
643510923SEvan.Yan@Sun.COM 		/* program the low word */
643610923SEvan.Yan@Sun.COM 
643710923SEvan.Yan@Sun.COM 		ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer));
643810923SEvan.Yan@Sun.COM 
643910923SEvan.Yan@Sun.COM 		phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
644010923SEvan.Yan@Sun.COM 		phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
644110923SEvan.Yan@Sun.COM 	} else {
644210923SEvan.Yan@Sun.COM 
644310923SEvan.Yan@Sun.COM 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
644410923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
6445*12765SScott.Carter@Oracle.COM 			request.ra_flags &= ~NDI_RA_ALLOC_BOUNDED;
644610923SEvan.Yan@Sun.COM 			/* allocate memory space from the allocator */
644710923SEvan.Yan@Sun.COM 			if (ndi_ra_alloc(ddi_get_parent(dip),
644810923SEvan.Yan@Sun.COM 			    &request, &answer, &alen,
644910923SEvan.Yan@Sun.COM 			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
645010923SEvan.Yan@Sun.COM 			    != NDI_SUCCESS) {
645110923SEvan.Yan@Sun.COM 				DEBUG0("Failed to allocate 64b mem\n");
645210923SEvan.Yan@Sun.COM 				pcicfg_unmap_phys(&h, &config);
645310923SEvan.Yan@Sun.COM 				return (1);
645410923SEvan.Yan@Sun.COM 			}
645510923SEvan.Yan@Sun.COM 			DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
645610923SEvan.Yan@Sun.COM 			    PCICFG_HIADDR(answer),
645710923SEvan.Yan@Sun.COM 			    PCICFG_LOADDR(answer),
645810923SEvan.Yan@Sun.COM 			    alen);
645910923SEvan.Yan@Sun.COM 
646010923SEvan.Yan@Sun.COM 			/* program the low word */
646110923SEvan.Yan@Sun.COM 
646210923SEvan.Yan@Sun.COM 			ddi_put32(h, (uint32_t *)v,
646310923SEvan.Yan@Sun.COM 			    (uint32_t)PCICFG_LOADDR(answer));
646410923SEvan.Yan@Sun.COM 
646510923SEvan.Yan@Sun.COM 			/* program the high word with value zero */
646610923SEvan.Yan@Sun.COM 			v += 4;
646710923SEvan.Yan@Sun.COM 			ddi_put32(h, (uint32_t *)v,
646810923SEvan.Yan@Sun.COM 			    (uint32_t)PCICFG_HIADDR(answer));
646910923SEvan.Yan@Sun.COM 
647010923SEvan.Yan@Sun.COM 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
647110923SEvan.Yan@Sun.COM 			phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
647210923SEvan.Yan@Sun.COM 			/*
647310923SEvan.Yan@Sun.COM 			 * currently support 32b address space
647410923SEvan.Yan@Sun.COM 			 * assignments only.
647510923SEvan.Yan@Sun.COM 			 */
647610923SEvan.Yan@Sun.COM 			phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^
647710923SEvan.Yan@Sun.COM 			    PCI_ADDR_MEM32;
647810923SEvan.Yan@Sun.COM 
647910923SEvan.Yan@Sun.COM 			break;
648010923SEvan.Yan@Sun.COM 
648110923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
648210923SEvan.Yan@Sun.COM 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
648310923SEvan.Yan@Sun.COM 			/* allocate memory space from the allocator */
648410923SEvan.Yan@Sun.COM 			if (ndi_ra_alloc(ddi_get_parent(dip),
648510923SEvan.Yan@Sun.COM 			    &request, &answer, &alen,
648610923SEvan.Yan@Sun.COM 			    NDI_RA_TYPE_MEM, NDI_RA_PASS)
648710923SEvan.Yan@Sun.COM 			    != NDI_SUCCESS) {
648810923SEvan.Yan@Sun.COM 				DEBUG0("Failed to allocate 32b mem\n");
648910923SEvan.Yan@Sun.COM 				pcicfg_unmap_phys(&h, &config);
649010923SEvan.Yan@Sun.COM 				return (1);
649110923SEvan.Yan@Sun.COM 			}
649210923SEvan.Yan@Sun.COM 
649310923SEvan.Yan@Sun.COM 			DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
649410923SEvan.Yan@Sun.COM 			    PCICFG_HIADDR(answer),
649510923SEvan.Yan@Sun.COM 			    PCICFG_LOADDR(answer),
649610923SEvan.Yan@Sun.COM 			    alen);
649710923SEvan.Yan@Sun.COM 
649810923SEvan.Yan@Sun.COM 			/* program the low word */
649910923SEvan.Yan@Sun.COM 
650010923SEvan.Yan@Sun.COM 			ddi_put32(h, (uint32_t *)v,
650110923SEvan.Yan@Sun.COM 			    (uint32_t)PCICFG_LOADDR(answer));
650210923SEvan.Yan@Sun.COM 
650310923SEvan.Yan@Sun.COM 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
650410923SEvan.Yan@Sun.COM 
650510923SEvan.Yan@Sun.COM 			break;
650610923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
650710923SEvan.Yan@Sun.COM 			/* allocate I/O space from the allocator */
650810923SEvan.Yan@Sun.COM 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
650910923SEvan.Yan@Sun.COM 			if (ndi_ra_alloc(ddi_get_parent(dip),
651010923SEvan.Yan@Sun.COM 			    &request, &answer, &alen,
651110923SEvan.Yan@Sun.COM 			    NDI_RA_TYPE_IO, NDI_RA_PASS)
651210923SEvan.Yan@Sun.COM 			    != NDI_SUCCESS) {
651310923SEvan.Yan@Sun.COM 				DEBUG0("Failed to allocate I/O\n");
651410923SEvan.Yan@Sun.COM 				pcicfg_unmap_phys(&h, &config);
651510923SEvan.Yan@Sun.COM 				return (1);
651610923SEvan.Yan@Sun.COM 			}
651710923SEvan.Yan@Sun.COM 			DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
651810923SEvan.Yan@Sun.COM 			    PCICFG_HIADDR(answer),
651910923SEvan.Yan@Sun.COM 			    PCICFG_LOADDR(answer),
652010923SEvan.Yan@Sun.COM 			    alen);
652110923SEvan.Yan@Sun.COM 
652210923SEvan.Yan@Sun.COM 			ddi_put32(h, (uint32_t *)v,
652310923SEvan.Yan@Sun.COM 			    (uint32_t)PCICFG_LOADDR(answer));
652410923SEvan.Yan@Sun.COM 
652510923SEvan.Yan@Sun.COM 			phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
652610923SEvan.Yan@Sun.COM 
652710923SEvan.Yan@Sun.COM 			break;
652810923SEvan.Yan@Sun.COM 		default:
652910923SEvan.Yan@Sun.COM 			DEBUG0("Unknown register type\n");
653010923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &config);
653110923SEvan.Yan@Sun.COM 			return (1);
653210923SEvan.Yan@Sun.COM 		} /* switch */
653310923SEvan.Yan@Sun.COM 	}
653410923SEvan.Yan@Sun.COM 
653510923SEvan.Yan@Sun.COM 	/*
653610923SEvan.Yan@Sun.COM 	 * Now that memory locations are assigned,
653710923SEvan.Yan@Sun.COM 	 * update the assigned address property.
653810923SEvan.Yan@Sun.COM 	 */
653910923SEvan.Yan@Sun.COM 
654010923SEvan.Yan@Sun.COM 	DEBUG1("updating assigned-addresss for %x\n",  phys_spec.pci_phys_hi);
654110923SEvan.Yan@Sun.COM 
654210923SEvan.Yan@Sun.COM 	if (pcicfg_update_assigned_prop(dip, &phys_spec)) {
654310923SEvan.Yan@Sun.COM 		pcicfg_unmap_phys(&h, &config);
654410923SEvan.Yan@Sun.COM 		return (1);
654510923SEvan.Yan@Sun.COM 	}
654610923SEvan.Yan@Sun.COM 
654710923SEvan.Yan@Sun.COM 	pcicfg_unmap_phys(&h, &config);
654810923SEvan.Yan@Sun.COM 
654910923SEvan.Yan@Sun.COM 	return (0);
655010923SEvan.Yan@Sun.COM }
655110923SEvan.Yan@Sun.COM 
655210923SEvan.Yan@Sun.COM static int
pcicfg_free_resource(dev_info_t * dip,pci_regspec_t phys_spec,pcicfg_flags_t flags)655310923SEvan.Yan@Sun.COM pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec,
655410923SEvan.Yan@Sun.COM     pcicfg_flags_t flags)
655510923SEvan.Yan@Sun.COM {
655610923SEvan.Yan@Sun.COM 	int offset;
655710923SEvan.Yan@Sun.COM 	pci_regspec_t config;
655810923SEvan.Yan@Sun.COM 	caddr_t virt, v;
655910923SEvan.Yan@Sun.COM 	ddi_device_acc_attr_t acc;
656010923SEvan.Yan@Sun.COM 	ddi_acc_handle_t h;
656110923SEvan.Yan@Sun.COM 	ndi_ra_request_t request;
656210923SEvan.Yan@Sun.COM 	int l;
656310923SEvan.Yan@Sun.COM 
656410923SEvan.Yan@Sun.COM 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
656510923SEvan.Yan@Sun.COM 
656610923SEvan.Yan@Sun.COM 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
656710923SEvan.Yan@Sun.COM 	config.pci_phys_hi &= ~PCI_REG_REG_M;
656810923SEvan.Yan@Sun.COM 	config.pci_phys_mid = config.pci_phys_low = 0;
656910923SEvan.Yan@Sun.COM 	config.pci_size_hi = config.pci_size_low = 0;
657010923SEvan.Yan@Sun.COM 
657110923SEvan.Yan@Sun.COM 	/*
657210923SEvan.Yan@Sun.COM 	 * Map in configuration space (temporarily)
657310923SEvan.Yan@Sun.COM 	 */
657410923SEvan.Yan@Sun.COM 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
657510923SEvan.Yan@Sun.COM 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
657610923SEvan.Yan@Sun.COM 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
657710923SEvan.Yan@Sun.COM 
657810923SEvan.Yan@Sun.COM 	if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
657910923SEvan.Yan@Sun.COM 		DEBUG0("Can not map in config space\n");
658010923SEvan.Yan@Sun.COM 		return (1);
658110923SEvan.Yan@Sun.COM 	}
658210923SEvan.Yan@Sun.COM 
658310923SEvan.Yan@Sun.COM 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
658410923SEvan.Yan@Sun.COM 
658510923SEvan.Yan@Sun.COM 	v = virt + offset;
658610923SEvan.Yan@Sun.COM 
658710923SEvan.Yan@Sun.COM 	/*
658810923SEvan.Yan@Sun.COM 	 * Use size stored in phys_spec parameter.
658910923SEvan.Yan@Sun.COM 	 */
659010923SEvan.Yan@Sun.COM 	l = phys_spec.pci_size_low;
659110923SEvan.Yan@Sun.COM 
659210923SEvan.Yan@Sun.COM 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
659310923SEvan.Yan@Sun.COM 
659410923SEvan.Yan@Sun.COM 		/* free memory back to the allocator */
659510923SEvan.Yan@Sun.COM 		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
659610923SEvan.Yan@Sun.COM 		    l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
659710923SEvan.Yan@Sun.COM 			DEBUG0("(ROM)Can not free 32b mem");
659810923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &config);
659910923SEvan.Yan@Sun.COM 			return (1);
660010923SEvan.Yan@Sun.COM 		}
660110923SEvan.Yan@Sun.COM 
660210923SEvan.Yan@Sun.COM 		/* Unmap the BAR by writing a zero */
660310923SEvan.Yan@Sun.COM 
660410923SEvan.Yan@Sun.COM 		if ((flags & PCICFG_FLAG_READ_ONLY) == 0)
660510923SEvan.Yan@Sun.COM 			ddi_put32(h, (uint32_t *)v, (uint32_t)0);
660610923SEvan.Yan@Sun.COM 	} else {
660710923SEvan.Yan@Sun.COM 
660810923SEvan.Yan@Sun.COM 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
6609*12765SScott.Carter@Oracle.COM 
661010923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
6611*12765SScott.Carter@Oracle.COM 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
661210923SEvan.Yan@Sun.COM 			/* free memory back to the allocator */
661310923SEvan.Yan@Sun.COM 			if (ndi_ra_free(ddi_get_parent(dip),
661410923SEvan.Yan@Sun.COM 			    PCICFG_LADDR(phys_spec.pci_phys_low,
661510923SEvan.Yan@Sun.COM 			    phys_spec.pci_phys_mid),
661610923SEvan.Yan@Sun.COM 			    l, NDI_RA_TYPE_MEM,
661710923SEvan.Yan@Sun.COM 			    NDI_RA_PASS) != NDI_SUCCESS) {
6618*12765SScott.Carter@Oracle.COM 				DEBUG0("Cannot free mem");
661910923SEvan.Yan@Sun.COM 				pcicfg_unmap_phys(&h, &config);
662010923SEvan.Yan@Sun.COM 				return (1);
662110923SEvan.Yan@Sun.COM 			}
662210923SEvan.Yan@Sun.COM 			break;
662310923SEvan.Yan@Sun.COM 
662410923SEvan.Yan@Sun.COM 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
662510923SEvan.Yan@Sun.COM 			/* free I/O space back to the allocator */
662610923SEvan.Yan@Sun.COM 			if (ndi_ra_free(ddi_get_parent(dip),
662710923SEvan.Yan@Sun.COM 			    phys_spec.pci_phys_low,
662810923SEvan.Yan@Sun.COM 			    l, NDI_RA_TYPE_IO,
662910923SEvan.Yan@Sun.COM 			    NDI_RA_PASS) != NDI_SUCCESS) {
663010923SEvan.Yan@Sun.COM 				DEBUG0("Can not free I/O space");
663110923SEvan.Yan@Sun.COM 				pcicfg_unmap_phys(&h, &config);
663210923SEvan.Yan@Sun.COM 				return (1);
663310923SEvan.Yan@Sun.COM 			}
663410923SEvan.Yan@Sun.COM 			break;
6635*12765SScott.Carter@Oracle.COM 
663610923SEvan.Yan@Sun.COM 		default:
663710923SEvan.Yan@Sun.COM 			DEBUG0("Unknown register type\n");
663810923SEvan.Yan@Sun.COM 			pcicfg_unmap_phys(&h, &config);
663910923SEvan.Yan@Sun.COM 			return (1);
664010923SEvan.Yan@Sun.COM 		} /* switch */
664110923SEvan.Yan@Sun.COM 	}
664210923SEvan.Yan@Sun.COM 
664310923SEvan.Yan@Sun.COM 	/*
664410923SEvan.Yan@Sun.COM 	 * Now that memory locations are assigned,
664510923SEvan.Yan@Sun.COM 	 * update the assigned address property.
664610923SEvan.Yan@Sun.COM 	 */
664710923SEvan.Yan@Sun.COM 
664810923SEvan.Yan@Sun.COM 	DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi);
664910923SEvan.Yan@Sun.COM 
665010923SEvan.Yan@Sun.COM 	if (pcicfg_remove_assigned_prop(dip, &phys_spec)) {
665110923SEvan.Yan@Sun.COM 		pcicfg_unmap_phys(&h, &config);
665210923SEvan.Yan@Sun.COM 		return (1);
665310923SEvan.Yan@Sun.COM 	}
665410923SEvan.Yan@Sun.COM 
665510923SEvan.Yan@Sun.COM 	pcicfg_unmap_phys(&h, &config);
665610923SEvan.Yan@Sun.COM 
665710923SEvan.Yan@Sun.COM 	return (0);
665810923SEvan.Yan@Sun.COM }
665910923SEvan.Yan@Sun.COM 
666010923SEvan.Yan@Sun.COM static int
pcicfg_remove_assigned_prop(dev_info_t * dip,pci_regspec_t * oldone)666110923SEvan.Yan@Sun.COM pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
666210923SEvan.Yan@Sun.COM {
666310923SEvan.Yan@Sun.COM 	int		alen, num_entries, i;
666410923SEvan.Yan@Sun.COM 	pci_regspec_t	*assigned, *assigned_copy;
666510923SEvan.Yan@Sun.COM 	uint_t		status;
666610923SEvan.Yan@Sun.COM 
666710923SEvan.Yan@Sun.COM 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
666810923SEvan.Yan@Sun.COM 	    "assigned-addresses", (caddr_t)&assigned, &alen);
666910923SEvan.Yan@Sun.COM 	switch (status) {
667010923SEvan.Yan@Sun.COM 		case DDI_PROP_SUCCESS:
667110923SEvan.Yan@Sun.COM 		break;
667210923SEvan.Yan@Sun.COM 		case DDI_PROP_NO_MEMORY:
667310923SEvan.Yan@Sun.COM 			DEBUG0("no memory for assigned-addresses property\n");
667410923SEvan.Yan@Sun.COM 			return (1);
667510923SEvan.Yan@Sun.COM 		default:
667610923SEvan.Yan@Sun.COM 			DEBUG0("assigned-addresses property does not exist\n");
667710923SEvan.Yan@Sun.COM 			return (0);
667810923SEvan.Yan@Sun.COM 	}
667910923SEvan.Yan@Sun.COM 
668010923SEvan.Yan@Sun.COM 	/*
668110923SEvan.Yan@Sun.COM 	 * Make a copy of old assigned-addresses property.
668210923SEvan.Yan@Sun.COM 	 */
668310923SEvan.Yan@Sun.COM 	assigned_copy = kmem_alloc(alen, KM_SLEEP);
668410923SEvan.Yan@Sun.COM 	bcopy(assigned, assigned_copy, alen);
668510923SEvan.Yan@Sun.COM 
668610923SEvan.Yan@Sun.COM 	status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses");
668710923SEvan.Yan@Sun.COM 
668810923SEvan.Yan@Sun.COM 	if (status != DDI_PROP_SUCCESS) {
668910923SEvan.Yan@Sun.COM 		/*
669010923SEvan.Yan@Sun.COM 		 * If "assigned-addresses" is retrieved from PROM, the
669110923SEvan.Yan@Sun.COM 		 * ndi_prop_remove() will fail.
669210923SEvan.Yan@Sun.COM 		 */
669310923SEvan.Yan@Sun.COM 		DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n",
669410923SEvan.Yan@Sun.COM 		    oldone->pci_phys_hi);
669510923SEvan.Yan@Sun.COM 
669610923SEvan.Yan@Sun.COM 		/*
669710923SEvan.Yan@Sun.COM 		 * Free up allocated memory
669810923SEvan.Yan@Sun.COM 		 */
669910923SEvan.Yan@Sun.COM 		kmem_free(assigned_copy, alen);
670010923SEvan.Yan@Sun.COM 		kmem_free((caddr_t)assigned, alen);
670110923SEvan.Yan@Sun.COM 
670210923SEvan.Yan@Sun.COM 		return (0);
670310923SEvan.Yan@Sun.COM 	}
670410923SEvan.Yan@Sun.COM 
670510923SEvan.Yan@Sun.COM 	num_entries = alen / sizeof (pci_regspec_t);
670610923SEvan.Yan@Sun.COM 
670710923SEvan.Yan@Sun.COM 	/*
670810923SEvan.Yan@Sun.COM 	 * Rebuild the assigned-addresses property.
670910923SEvan.Yan@Sun.COM 	 */
671010923SEvan.Yan@Sun.COM 	for (i = 0; i < num_entries; i++) {
671110923SEvan.Yan@Sun.COM 		if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) {
671210923SEvan.Yan@Sun.COM 			(void) pcicfg_update_assigned_prop(dip,
671310923SEvan.Yan@Sun.COM 			    &assigned_copy[i]);
671410923SEvan.Yan@Sun.COM 		}
671510923SEvan.Yan@Sun.COM 	}
671610923SEvan.Yan@Sun.COM 
671710923SEvan.Yan@Sun.COM 	/*
671810923SEvan.Yan@Sun.COM 	 * Free the copy of the original assigned-addresses.
671910923SEvan.Yan@Sun.COM 	 */
672010923SEvan.Yan@Sun.COM 	kmem_free(assigned_copy, alen);
672110923SEvan.Yan@Sun.COM 
672210923SEvan.Yan@Sun.COM 	/*
672310923SEvan.Yan@Sun.COM 	 * Don't forget to free up memory from ddi_getlongprop
672410923SEvan.Yan@Sun.COM 	 */
672510923SEvan.Yan@Sun.COM 	kmem_free((caddr_t)assigned, alen);
672610923SEvan.Yan@Sun.COM 
672710923SEvan.Yan@Sun.COM 	return (0);
672810923SEvan.Yan@Sun.COM }
672910923SEvan.Yan@Sun.COM 
673010923SEvan.Yan@Sun.COM static int
pcicfg_map_phys(dev_info_t * dip,pci_regspec_t * phys_spec,caddr_t * addrp,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handlep)673110923SEvan.Yan@Sun.COM pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
673210923SEvan.Yan@Sun.COM 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
673310923SEvan.Yan@Sun.COM 	ddi_acc_handle_t *handlep)
673410923SEvan.Yan@Sun.COM {
673510923SEvan.Yan@Sun.COM 	ddi_map_req_t mr;
673610923SEvan.Yan@Sun.COM 	ddi_acc_hdl_t *hp;
673710923SEvan.Yan@Sun.COM 	int result;
673810923SEvan.Yan@Sun.COM 
673910923SEvan.Yan@Sun.COM 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
674010923SEvan.Yan@Sun.COM 	hp = impl_acc_hdl_get(*handlep);
674110923SEvan.Yan@Sun.COM 	hp->ah_vers = VERS_ACCHDL;
674210923SEvan.Yan@Sun.COM 	hp->ah_dip = dip;
674310923SEvan.Yan@Sun.COM 	hp->ah_rnumber = 0;
674410923SEvan.Yan@Sun.COM 	hp->ah_offset = 0;
674510923SEvan.Yan@Sun.COM 	hp->ah_len = 0;
674610923SEvan.Yan@Sun.COM 	hp->ah_acc = *accattrp;
674710923SEvan.Yan@Sun.COM 
674810923SEvan.Yan@Sun.COM 	mr.map_op = DDI_MO_MAP_LOCKED;
674910923SEvan.Yan@Sun.COM 	mr.map_type = DDI_MT_REGSPEC;
675010923SEvan.Yan@Sun.COM 	mr.map_obj.rp = (struct regspec *)phys_spec;
675110923SEvan.Yan@Sun.COM 	mr.map_prot = PROT_READ | PROT_WRITE;
675210923SEvan.Yan@Sun.COM 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
675310923SEvan.Yan@Sun.COM 	mr.map_handlep = hp;
675410923SEvan.Yan@Sun.COM 	mr.map_vers = DDI_MAP_VERSION;
675510923SEvan.Yan@Sun.COM 
675610923SEvan.Yan@Sun.COM 	result = ddi_map(dip, &mr, 0, 0, addrp);
675710923SEvan.Yan@Sun.COM 
675810923SEvan.Yan@Sun.COM 	if (result != DDI_SUCCESS) {
675910923SEvan.Yan@Sun.COM 		impl_acc_hdl_free(*handlep);
676010923SEvan.Yan@Sun.COM 		*handlep = (ddi_acc_handle_t)NULL;
676110923SEvan.Yan@Sun.COM 	} else {
676210923SEvan.Yan@Sun.COM 		hp->ah_addr = *addrp;
676310923SEvan.Yan@Sun.COM 	}
676410923SEvan.Yan@Sun.COM 
676510923SEvan.Yan@Sun.COM 	return (result);
676610923SEvan.Yan@Sun.COM }
676710923SEvan.Yan@Sun.COM 
676810923SEvan.Yan@Sun.COM void
pcicfg_unmap_phys(ddi_acc_handle_t * handlep,pci_regspec_t * ph)676910923SEvan.Yan@Sun.COM pcicfg_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
677010923SEvan.Yan@Sun.COM {
677110923SEvan.Yan@Sun.COM 	ddi_map_req_t mr;
677210923SEvan.Yan@Sun.COM 	ddi_acc_hdl_t *hp;
677310923SEvan.Yan@Sun.COM 
677410923SEvan.Yan@Sun.COM 	hp = impl_acc_hdl_get(*handlep);
677510923SEvan.Yan@Sun.COM 	ASSERT(hp);
677610923SEvan.Yan@Sun.COM 
677710923SEvan.Yan@Sun.COM 	mr.map_op = DDI_MO_UNMAP;
677810923SEvan.Yan@Sun.COM 	mr.map_type = DDI_MT_REGSPEC;
677910923SEvan.Yan@Sun.COM 	mr.map_obj.rp = (struct regspec *)ph;
678010923SEvan.Yan@Sun.COM 	mr.map_prot = PROT_READ | PROT_WRITE;
678110923SEvan.Yan@Sun.COM 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
678210923SEvan.Yan@Sun.COM 	mr.map_handlep = hp;
678310923SEvan.Yan@Sun.COM 	mr.map_vers = DDI_MAP_VERSION;
678410923SEvan.Yan@Sun.COM 
678510923SEvan.Yan@Sun.COM 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
678610923SEvan.Yan@Sun.COM 	    hp->ah_len, &hp->ah_addr);
678710923SEvan.Yan@Sun.COM 
678810923SEvan.Yan@Sun.COM 	impl_acc_hdl_free(*handlep);
678910923SEvan.Yan@Sun.COM 	*handlep = (ddi_acc_handle_t)NULL;
679010923SEvan.Yan@Sun.COM }
679110923SEvan.Yan@Sun.COM 
679210923SEvan.Yan@Sun.COM static int
pcicfg_ari_configure(dev_info_t * dip)679310923SEvan.Yan@Sun.COM pcicfg_ari_configure(dev_info_t *dip)
679410923SEvan.Yan@Sun.COM {
679510923SEvan.Yan@Sun.COM 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
679610923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
679710923SEvan.Yan@Sun.COM 
679810923SEvan.Yan@Sun.COM 	/*
679910923SEvan.Yan@Sun.COM 	 * Until we have resource balancing, dynamically configure
680010923SEvan.Yan@Sun.COM 	 * ARI functions without firmware assistamce.
680110923SEvan.Yan@Sun.COM 	 */
680210923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
680310923SEvan.Yan@Sun.COM }
680410923SEvan.Yan@Sun.COM 
680510923SEvan.Yan@Sun.COM #ifdef DEBUG
680610923SEvan.Yan@Sun.COM static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)680710923SEvan.Yan@Sun.COM debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
680810923SEvan.Yan@Sun.COM 	uintptr_t a4, uintptr_t a5)
680910923SEvan.Yan@Sun.COM {
681010923SEvan.Yan@Sun.COM 	if (pcicfg_debug == 1) {
681110923SEvan.Yan@Sun.COM 		prom_printf("pcicfg: ");
681210923SEvan.Yan@Sun.COM 		prom_printf(fmt, a1, a2, a3, a4, a5);
681310923SEvan.Yan@Sun.COM 	} else
681410923SEvan.Yan@Sun.COM 		if (pcicfg_debug)
681510923SEvan.Yan@Sun.COM 			cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
681610923SEvan.Yan@Sun.COM }
681710923SEvan.Yan@Sun.COM #endif
681811245SZhijun.Fu@Sun.COM 
681911245SZhijun.Fu@Sun.COM /*
682011245SZhijun.Fu@Sun.COM  * Return true if the devinfo node is in a PCI Express hierarchy.
682111245SZhijun.Fu@Sun.COM  */
682211245SZhijun.Fu@Sun.COM static boolean_t
is_pcie_fabric(dev_info_t * dip)682311245SZhijun.Fu@Sun.COM is_pcie_fabric(dev_info_t *dip)
682411245SZhijun.Fu@Sun.COM {
682511245SZhijun.Fu@Sun.COM 	dev_info_t *root = ddi_root_node();
682611245SZhijun.Fu@Sun.COM 	dev_info_t *pdip;
682711245SZhijun.Fu@Sun.COM 	boolean_t found = B_FALSE;
682811245SZhijun.Fu@Sun.COM 	char *bus;
682911245SZhijun.Fu@Sun.COM 
683011245SZhijun.Fu@Sun.COM 	/*
683111245SZhijun.Fu@Sun.COM 	 * Does this device reside in a pcie fabric ?
683211245SZhijun.Fu@Sun.COM 	 */
683311245SZhijun.Fu@Sun.COM 	for (pdip = dip; pdip && (pdip != root) && !found;
683411245SZhijun.Fu@Sun.COM 	    pdip = ddi_get_parent(pdip)) {
683511245SZhijun.Fu@Sun.COM 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
683611245SZhijun.Fu@Sun.COM 		    DDI_PROP_DONTPASS, "device_type", &bus) !=
683711245SZhijun.Fu@Sun.COM 		    DDI_PROP_SUCCESS)
683811245SZhijun.Fu@Sun.COM 			break;
683911245SZhijun.Fu@Sun.COM 
684011245SZhijun.Fu@Sun.COM 		if (strcmp(bus, "pciex") == 0)
684111245SZhijun.Fu@Sun.COM 			found = B_TRUE;
684211245SZhijun.Fu@Sun.COM 
684311245SZhijun.Fu@Sun.COM 		ddi_prop_free(bus);
684411245SZhijun.Fu@Sun.COM 	}
684511245SZhijun.Fu@Sun.COM 
684611245SZhijun.Fu@Sun.COM 	return (found);
684711245SZhijun.Fu@Sun.COM }
6848