xref: /illumos-gate/usr/src/uts/intel/io/pci/pci_boot.c (revision 6ecc4705)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
575bcd456Sjg  * Common Development and Distribution License (the "License").
675bcd456Sjg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
220db3240dSStephen Hanson  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23bfa93d39SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
243349e36eSPaul Winder  * Copyright 2019 Western Digital Corporation
25*6ecc4705SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
26*6ecc4705SAndy Fiddaman  */
27*6ecc4705SAndy Fiddaman 
28*6ecc4705SAndy Fiddaman /*
29*6ecc4705SAndy Fiddaman  * PCI bus enumeration and device programming are done in several passes. The
30*6ecc4705SAndy Fiddaman  * following is a high level overview of this process.
31*6ecc4705SAndy Fiddaman  *
32*6ecc4705SAndy Fiddaman  * pci_enumerate(reprogram=0)
33*6ecc4705SAndy Fiddaman  *				The main entry point to PCI bus enumeration is
34*6ecc4705SAndy Fiddaman  *				pci_enumerate(). This function is invoked
35*6ecc4705SAndy Fiddaman  *				twice, once to set up the PCI portion of the
36*6ecc4705SAndy Fiddaman  *				device tree, and then a second time to
37*6ecc4705SAndy Fiddaman  *				reprogram any devices which were not set up by
38*6ecc4705SAndy Fiddaman  *				the system firmware. On this first call, the
39*6ecc4705SAndy Fiddaman  *				reprogram parameter is set to 0.
40*6ecc4705SAndy Fiddaman  *   add_pci_fixes()
41*6ecc4705SAndy Fiddaman  *	enumerate_bus_devs(CONFIG_FIX)
42*6ecc4705SAndy Fiddaman  *	    <foreach bus>
43*6ecc4705SAndy Fiddaman  *	        process_devfunc(CONFIG_FIX)
44*6ecc4705SAndy Fiddaman  *				Some devices need a specific action taking in
45*6ecc4705SAndy Fiddaman  *				order for subsequent enumeration to be
46*6ecc4705SAndy Fiddaman  *				successful. add_pci_fixes() retrieves the
47*6ecc4705SAndy Fiddaman  *				vendor and device IDs for each item on the bus
48*6ecc4705SAndy Fiddaman  *				and applies fixes as required. It also creates
49*6ecc4705SAndy Fiddaman  *				a list which is used by undo_pci_fixes() to
50*6ecc4705SAndy Fiddaman  *				reverse the process later.
51*6ecc4705SAndy Fiddaman  *   pci_setup_tree()
52*6ecc4705SAndy Fiddaman  *	enumerate_bus_devs(CONFIG_INFO)
53*6ecc4705SAndy Fiddaman  *	    <foreach bus>
54*6ecc4705SAndy Fiddaman  *	        process_devfunc(CONFIG_INFO)
55*6ecc4705SAndy Fiddaman  *	            <set up most device properties>
56*6ecc4705SAndy Fiddaman  *				The next stage is to enumerate the bus and set
57*6ecc4705SAndy Fiddaman  *				up the bulk of the properties for each device.
58*6ecc4705SAndy Fiddaman  *				This is where the generic properties such as
59*6ecc4705SAndy Fiddaman  *				'device-id' are created.
60*6ecc4705SAndy Fiddaman  *		    <if PPB device>
61*6ecc4705SAndy Fiddaman  *			add_ppb_props()
62*6ecc4705SAndy Fiddaman  *				For a PCI-to-PCI bridge (ppb) device, any
63*6ecc4705SAndy Fiddaman  *				memory ranges for IO, memory or pre-fetchable
64*6ecc4705SAndy Fiddaman  *				memory that have been programmed by the system
65*6ecc4705SAndy Fiddaman  *				firmware (BIOS/EFI) are retrieved and stored in
66*6ecc4705SAndy Fiddaman  *				bus-specific lists (pci_bus_res[bus].io_avail,
67*6ecc4705SAndy Fiddaman  *				mem_avail and pmem_avail). The contents of
68*6ecc4705SAndy Fiddaman  *				these lists are used to set the initial 'ranges'
69*6ecc4705SAndy Fiddaman  *				property on the ppb device. Later, as children
70*6ecc4705SAndy Fiddaman  *				are found for this bridge, resources will be
71*6ecc4705SAndy Fiddaman  *				removed from these avail lists as necessary.
72*6ecc4705SAndy Fiddaman  *				This is an initial pass so the ppb devices can
73*6ecc4705SAndy Fiddaman  *				still be reprogrammed later in fix_ppb_res().
74*6ecc4705SAndy Fiddaman  *		    <else>
75*6ecc4705SAndy Fiddaman  *			<add to list of non-PPB devices for the bus>
76*6ecc4705SAndy Fiddaman  *				Any non-PPB device on the bus is recorded in a
77*6ecc4705SAndy Fiddaman  *				bus-specific list, to be set up (and possibly
78*6ecc4705SAndy Fiddaman  *				reprogrammed) later.
79*6ecc4705SAndy Fiddaman  *		    add_reg_props(CONFIG_INFO)
80*6ecc4705SAndy Fiddaman  *				The final step in this phase is to add the
81*6ecc4705SAndy Fiddaman  *				initial 'reg' and 'assigned-addresses'
82*6ecc4705SAndy Fiddaman  *				properties to all devices. At the same time,
83*6ecc4705SAndy Fiddaman  *				any IO or memory ranges which have been
84*6ecc4705SAndy Fiddaman  *				assigned to the bus are moved from the avail
85*6ecc4705SAndy Fiddaman  *				list to the corresponding used one. If no
86*6ecc4705SAndy Fiddaman  *				resources have been assigned to a device at
87*6ecc4705SAndy Fiddaman  *				this stage, then it is flagged for subsequent
88*6ecc4705SAndy Fiddaman  *				reprogramming.
89*6ecc4705SAndy Fiddaman  *     undo_pci_fixes()
90*6ecc4705SAndy Fiddaman  *				Any fixes which were applied in add_pci_fixes()
91*6ecc4705SAndy Fiddaman  *				are now undone before returning, using the
92*6ecc4705SAndy Fiddaman  *				undo list which was created earier.
93*6ecc4705SAndy Fiddaman  *
94*6ecc4705SAndy Fiddaman  * pci_enumerate(reprogram=1)
95*6ecc4705SAndy Fiddaman  *				The second bus enumeration pass is to take care
96*6ecc4705SAndy Fiddaman  *				of any devices that were not set up by the
97*6ecc4705SAndy Fiddaman  *				system firmware. These devices were flagged
98*6ecc4705SAndy Fiddaman  *				during the first pass. This pass is bracketed
99*6ecc4705SAndy Fiddaman  *				by the same pci fix application and removal as
100*6ecc4705SAndy Fiddaman  *				the first.
101*6ecc4705SAndy Fiddaman  *   add_pci_fixes()
102*6ecc4705SAndy Fiddaman  *				As for first pass.
103*6ecc4705SAndy Fiddaman  *   pci_reprogram()
104*6ecc4705SAndy Fiddaman  *	pci_scan_bbn()
105*6ecc4705SAndy Fiddaman  *				The ACPI namespace is scanned for top-level
106*6ecc4705SAndy Fiddaman  *				instances of _BBN in order to enumerate the
107*6ecc4705SAndy Fiddaman  *				root-bridges in the system. If a root bridge is
108*6ecc4705SAndy Fiddaman  *				found that has not been previously discovered
109*6ecc4705SAndy Fiddaman  *				(existence inferred through its children) then
110*6ecc4705SAndy Fiddaman  *				it is added to the system.
111*6ecc4705SAndy Fiddaman  *	<foreach ROOT bus>
112*6ecc4705SAndy Fiddaman  *	    populate_bus_res()
113*6ecc4705SAndy Fiddaman  *				Find resources associated with this root bus
114*6ecc4705SAndy Fiddaman  *				from either ACPI or BIOS tables. See
115*6ecc4705SAndy Fiddaman  *				find_bus_res() in pci_resource.c
116*6ecc4705SAndy Fiddaman  *	<foreach bus>
117*6ecc4705SAndy Fiddaman  *	    fix_ppb_res()
118*6ecc4705SAndy Fiddaman  *				Reprogram pci(e) bridges which have not already
119*6ecc4705SAndy Fiddaman  *				had resources assigned, or which are under a
120*6ecc4705SAndy Fiddaman  *				bus that has been flagged for reprogramming.
121*6ecc4705SAndy Fiddaman  *				If the parent bus has not been flagged, then IO
122*6ecc4705SAndy Fiddaman  *				space is reprogrammed only if there are no
123*6ecc4705SAndy Fiddaman  *				assigned IO resources. Memory space is
124*6ecc4705SAndy Fiddaman  *				reprogrammed only if there is both no assigned
125*6ecc4705SAndy Fiddaman  *				ordinary memory AND no assigned pre-fetchable
126*6ecc4705SAndy Fiddaman  *				memory. However, if memory reprogramming is
127*6ecc4705SAndy Fiddaman  *				necessary then both ordinary and prefetch are
128*6ecc4705SAndy Fiddaman  *				done together so that both memory ranges end up
129*6ecc4705SAndy Fiddaman  *				in the avail lists for add_reg_props() to find
130*6ecc4705SAndy Fiddaman  *				later.
131*6ecc4705SAndy Fiddaman  *	    enumerate_bus_devs(CONFIG_NEW)
132*6ecc4705SAndy Fiddaman  *		<foreach non-PPB device on the bus>
133*6ecc4705SAndy Fiddaman  *		    add_reg_props(CONFIG_NEW)
134*6ecc4705SAndy Fiddaman  *				Using the list of non-PPB devices on the bus
135*6ecc4705SAndy Fiddaman  *				which was assembled during the first pass, add
136*6ecc4705SAndy Fiddaman  *				or update the 'reg' and 'assigned-address'
137*6ecc4705SAndy Fiddaman  *				properties for these devices. For devices which
138*6ecc4705SAndy Fiddaman  *				have been flagged for reprogramming or have no
139*6ecc4705SAndy Fiddaman  *				assigned resources, this is where resources are
140*6ecc4705SAndy Fiddaman  *				finally assigned and programmed into the
141*6ecc4705SAndy Fiddaman  *				device. This can result in these properties
142*6ecc4705SAndy Fiddaman  *				changing from their previous values.
143*6ecc4705SAndy Fiddaman  *	<foreach bus>
144*6ecc4705SAndy Fiddaman  *	    add_bus_available_prop()
145*6ecc4705SAndy Fiddaman  *				Finally, the 'available' properties is set on
146*6ecc4705SAndy Fiddaman  *				each device, representing that device's final
147*6ecc4705SAndy Fiddaman  *				unallocated (available) IO and memory ranges.
148*6ecc4705SAndy Fiddaman  *   undo_pci_fixes()
149*6ecc4705SAndy Fiddaman  *				As for first pass.
1507c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate #include <sys/types.h>
1537c478bd9Sstevel@tonic-gate #include <sys/stat.h>
154ffa17327SGuoli Shu #include <sys/sysmacros.h>
1557c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
1567c478bd9Sstevel@tonic-gate #include <sys/pci.h>
1577c478bd9Sstevel@tonic-gate #include <sys/pci_impl.h>
158c0da6274SZhi-Jun Robin Fu #include <sys/pcie_impl.h>
1597c478bd9Sstevel@tonic-gate #include <sys/memlist.h>
1607c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
16170025d76Sjohnny #include <io/pci/mps_table.h>
162c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
163c88420b3Sdmick #include <sys/pci_cfgspace.h>
164c88420b3Sdmick #include <sys/pci_cfgspace_impl.h>
165c88420b3Sdmick #include <sys/psw.h>
16609f67678Sanish #include "../../../../common/pci/pci_strings.h"
167c8589f13Ssethg #include <sys/apic.h>
1688a5a0d1eSanish #include <io/pciex/pcie_nvidia.h>
16926947304SEvan Yan #include <sys/hotplug/pci/pciehpc_acpi.h>
17025145214Smyers #include <sys/acpi/acpi.h>
17125145214Smyers #include <sys/acpica.h>
17294f1124eSVikram Hegde #include <sys/iommulib.h>
17300dfdf4aSDana Myers #include <sys/devcache.h>
174c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc_x86.h>
1767c478bd9Sstevel@tonic-gate #define	pci_getb	(*pci_getb_func)
1777c478bd9Sstevel@tonic-gate #define	pci_getw	(*pci_getw_func)
1787c478bd9Sstevel@tonic-gate #define	pci_getl	(*pci_getl_func)
1797c478bd9Sstevel@tonic-gate #define	pci_putb	(*pci_putb_func)
1807c478bd9Sstevel@tonic-gate #define	pci_putw	(*pci_putw_func)
1817c478bd9Sstevel@tonic-gate #define	pci_putl	(*pci_putl_func)
182*6ecc4705SAndy Fiddaman #define	dcmn_err	if (pci_boot_debug != 0) cmn_err
183*6ecc4705SAndy Fiddaman #define	bus_debug(bus)	(pci_boot_debug != 0 && pci_debug_bus_start != -1 && \
184*6ecc4705SAndy Fiddaman 	    pci_debug_bus_end != -1 && (bus) >= pci_debug_bus_start && \
185*6ecc4705SAndy Fiddaman 	    (bus) <= pci_debug_bus_end)
186*6ecc4705SAndy Fiddaman #define	dump_memlists(tag, bus) \
187*6ecc4705SAndy Fiddaman 	if (bus_debug((bus))) dump_memlists_impl((tag), (bus))
1897c478bd9Sstevel@tonic-gate #define	CONFIG_INFO	0
1907c478bd9Sstevel@tonic-gate #define	CONFIG_UPDATE	1
1917c478bd9Sstevel@tonic-gate #define	CONFIG_NEW	2
192bd87be88Ssethg #define	CONFIG_FIX	3
19370025d76Sjohnny #define	COMPAT_BUFSIZE	512
19505f867c3Sgs #define	PPB_IO_ALIGNMENT	0x1000		/* 4K aligned */
19605f867c3Sgs #define	PPB_MEM_ALIGNMENT	0x100000	/* 1M aligned */
197ffa17327SGuoli Shu /* round down to nearest power of two */
198ffa17327SGuoli Shu #define	P2LE(align)					\
199ffa17327SGuoli Shu 	{						\
200ffa17327SGuoli Shu 		int i = 0;				\
201ffa17327SGuoli Shu 		while (align >>= 1)			\
202ffa17327SGuoli Shu 			i ++;				\
203ffa17327SGuoli Shu 		align = 1 << i;				\
204ffa17327SGuoli Shu 	}						\
2062f283da5SDan Mick /* for is_vga and list_is_vga_only */
2072f283da5SDan Mick 
2082f283da5SDan Mick enum io_mem {
2092f283da5SDan Mick 	IO,
2102f283da5SDan Mick 	MEM
2112f283da5SDan Mick };
2122f283da5SDan Mick 
213*6ecc4705SAndy Fiddaman /* for get_parbus_res */
214*6ecc4705SAndy Fiddaman 
215*6ecc4705SAndy Fiddaman enum parbus_mem {
216*6ecc4705SAndy Fiddaman 	PB_IO,
217*6ecc4705SAndy Fiddaman 	PB_MEM,
218*6ecc4705SAndy Fiddaman 	PB_PMEM
219*6ecc4705SAndy Fiddaman };
220*6ecc4705SAndy Fiddaman 
221*6ecc4705SAndy Fiddaman 
222bd87be88Ssethg /* See AMD-8111 Datasheet Rev 3.03, Page 149: */
223bd87be88Ssethg #define	LPC_IO_CONTROL_REG_1	0x40
224bd87be88Ssethg #define	AMD8111_ENABLENMI	(uint8_t)0x80
225bd87be88Ssethg #define	DEVID_AMD8111_LPC	0x7468
227bd87be88Ssethg struct pci_fixundo {
228bd87be88Ssethg 	uint8_t			bus;
229bd87be88Ssethg 	uint8_t			dev;
230bd87be88Ssethg 	uint8_t			fn;
231bd87be88Ssethg 	void			(*undofn)(uint8_t, uint8_t, uint8_t);
232bd87be88Ssethg 	struct pci_fixundo	*next;
233bd87be88Ssethg };
23505f867c3Sgs struct pci_devfunc {
23605f867c3Sgs 	struct pci_devfunc *next;
23705f867c3Sgs 	dev_info_t *dip;
23805f867c3Sgs 	uchar_t dev;
23905f867c3Sgs 	uchar_t func;
24005f867c3Sgs 	boolean_t reprogram;	/* this device needs to be reprogrammed */
24105f867c3Sgs };
2437ff178cdSJimmy Vetayases extern int apic_nvidia_io_max;
24478323854SJudy Chen extern int pseudo_isa;
24547310cedSDana Myers extern int pci_bios_maxbus;
2467c478bd9Sstevel@tonic-gate static uchar_t max_dev_pci = 32;	/* PCI standard */
2477c478bd9Sstevel@tonic-gate int pci_boot_debug = 0;
248*6ecc4705SAndy Fiddaman int pci_debug_bus_start = -1;
249*6ecc4705SAndy Fiddaman int pci_debug_bus_end = -1;
2507c478bd9Sstevel@tonic-gate extern struct memlist *find_bus_res(int, int);
251bd87be88Ssethg static struct pci_fixundo *undolist = NULL;
25205f867c3Sgs static int num_root_bus = 0;	/* count of root buses */
2538fc7923fSDana Myers extern volatile int acpi_resource_discovery;
254c0da6274SZhi-Jun Robin Fu extern uint64_t mcfg_mem_base;
255c0da6274SZhi-Jun Robin Fu extern void pci_cfgacc_add_workaround(uint16_t, uchar_t, uchar_t);
256c0da6274SZhi-Jun Robin Fu extern dev_info_t *pcie_get_rc_dip(dev_info_t *);
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * Module prototypes
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate static void enumerate_bus_devs(uchar_t bus, int config_op);
2627c478bd9Sstevel@tonic-gate static void create_root_bus_dip(uchar_t bus);
26305f867c3Sgs static void process_devfunc(uchar_t, uchar_t, uchar_t, uchar_t,
2647c478bd9Sstevel@tonic-gate     ushort_t, int);
2657c478bd9Sstevel@tonic-gate static void add_compatible(dev_info_t *, ushort_t, ushort_t,
26670025d76Sjohnny     ushort_t, ushort_t, uchar_t, uint_t, int);
2677c478bd9Sstevel@tonic-gate static int add_reg_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int, int);
26849fbdd30SErwin T Tsaur static void add_ppb_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int,
26949fbdd30SErwin T Tsaur     ushort_t);
2707c478bd9Sstevel@tonic-gate static void add_model_prop(dev_info_t *, uint_t);
2717c478bd9Sstevel@tonic-gate static void add_bus_range_prop(int);
272b1f176e8Sjg static void add_bus_slot_names_prop(int);
2738fc7923fSDana Myers static void add_ranges_prop(int, int);
2747c478bd9Sstevel@tonic-gate static void add_bus_available_prop(int);
27549fbdd30SErwin T Tsaur static int get_pci_cap(uchar_t bus, uchar_t dev, uchar_t func, uint8_t cap_id);
27605f867c3Sgs static void fix_ppb_res(uchar_t, boolean_t);
277f55ce205Sszhou static void alloc_res_array();
278c8589f13Ssethg static void create_ioapic_node(int bus, int dev, int fn, ushort_t vendorid,
279c8589f13Ssethg     ushort_t deviceid);
280d57b3b3dSprasad static void pciex_slot_names_prop(dev_info_t *, ushort_t);
2818fc7923fSDana Myers static void populate_bus_res(uchar_t bus);
2828fc7923fSDana Myers static void memlist_remove_list(struct memlist **list,
2838fc7923fSDana Myers     struct memlist *remove_list);
284c0da6274SZhi-Jun Robin Fu static void ck804_fix_aer_ptr(dev_info_t *, pcie_req_id_t);
28600dfdf4aSDana Myers static void pci_scan_bbn(void);
28700dfdf4aSDana Myers static int pci_unitaddr_cache_valid(void);
28800dfdf4aSDana Myers static int pci_bus_unitaddr(int);
28900dfdf4aSDana Myers static void pci_unitaddr_cache_create(void);
29000dfdf4aSDana Myers 
29100dfdf4aSDana Myers static int pci_cache_unpack_nvlist(nvf_handle_t, nvlist_t *, char *);
29200dfdf4aSDana Myers static int pci_cache_pack_nvlist(nvf_handle_t, nvlist_t **);
29300dfdf4aSDana Myers static void pci_cache_free_list(nvf_handle_t);
29400dfdf4aSDana Myers 
29575bcd456Sjg extern int pci_slot_names_prop(int, char *, int);
297ee8c1d4aSdm /* set non-zero to force PCI peer-bus renumbering */
29825145214Smyers int pci_bus_always_renumber = 0;
3001d6b7b34SJudy Chen /*
3011d6b7b34SJudy Chen  * used to register ISA resource usage which must not be made
3021d6b7b34SJudy Chen  * "available" from other PCI node' resource maps
3031d6b7b34SJudy Chen  */
3041d6b7b34SJudy Chen static struct {
3052f283da5SDan Mick 	struct memlist *io_used;
3062f283da5SDan Mick 	struct memlist *mem_used;
3071d6b7b34SJudy Chen } isa_res;
3081d6b7b34SJudy Chen 
30900dfdf4aSDana Myers /*
31000dfdf4aSDana Myers  * PCI unit-address cache management
31100dfdf4aSDana Myers  */
31200dfdf4aSDana Myers static nvf_ops_t pci_unitaddr_cache_ops = {
31300dfdf4aSDana Myers 	"/etc/devices/pci_unitaddr_persistent",	/* path to cache */
31400dfdf4aSDana Myers 	pci_cache_unpack_nvlist,		/* read in nvlist form */
31500dfdf4aSDana Myers 	pci_cache_pack_nvlist,			/* convert to nvlist form */
31600dfdf4aSDana Myers 	pci_cache_free_list,			/* free data list */
31700dfdf4aSDana Myers 	NULL					/* write complete callback */
31800dfdf4aSDana Myers };
31900dfdf4aSDana Myers 
32000dfdf4aSDana Myers typedef struct {
32100dfdf4aSDana Myers 	list_node_t	pua_nodes;
32200dfdf4aSDana Myers 	int		pua_index;
32300dfdf4aSDana Myers 	int		pua_addr;
32400dfdf4aSDana Myers } pua_node_t;
32500dfdf4aSDana Myers 
32600dfdf4aSDana Myers nvf_handle_t	puafd_handle;
32700dfdf4aSDana Myers int		pua_cache_valid = 0;
32800dfdf4aSDana Myers 
329*6ecc4705SAndy Fiddaman static void
dump_memlists_impl(const char * tag,int bus)330*6ecc4705SAndy Fiddaman dump_memlists_impl(const char *tag, int bus)
331*6ecc4705SAndy Fiddaman {
332*6ecc4705SAndy Fiddaman 	printf("Memlist dump at %s - bus %x\n", tag, bus);
333*6ecc4705SAndy Fiddaman 	if (pci_bus_res[bus].io_used != NULL) {
334*6ecc4705SAndy Fiddaman 		printf("    io_used ");
335*6ecc4705SAndy Fiddaman 		memlist_dump(pci_bus_res[bus].io_used);
336*6ecc4705SAndy Fiddaman 	}
337*6ecc4705SAndy Fiddaman 	if (pci_bus_res[bus].io_avail != NULL) {
338*6ecc4705SAndy Fiddaman 		printf("    io_avail ");
339*6ecc4705SAndy Fiddaman 		memlist_dump(pci_bus_res[bus].io_avail);
340*6ecc4705SAndy Fiddaman 	}
341*6ecc4705SAndy Fiddaman 	if (pci_bus_res[bus].mem_used != NULL) {
342*6ecc4705SAndy Fiddaman 		printf("    mem_used ");
343*6ecc4705SAndy Fiddaman 		memlist_dump(pci_bus_res[bus].mem_used);
344*6ecc4705SAndy Fiddaman 	}
345*6ecc4705SAndy Fiddaman 	if (pci_bus_res[bus].mem_avail != NULL) {
346*6ecc4705SAndy Fiddaman 		printf("    mem_avail ");
347*6ecc4705SAndy Fiddaman 		memlist_dump(pci_bus_res[bus].mem_avail);
348*6ecc4705SAndy Fiddaman 	}
349*6ecc4705SAndy Fiddaman 	if (pci_bus_res[bus].pmem_used != NULL) {
350*6ecc4705SAndy Fiddaman 		printf("    pmem_used ");
351*6ecc4705SAndy Fiddaman 		memlist_dump(pci_bus_res[bus].pmem_used);
352*6ecc4705SAndy Fiddaman 	}
353*6ecc4705SAndy Fiddaman 	if (pci_bus_res[bus].pmem_avail != NULL) {
354*6ecc4705SAndy Fiddaman 		printf("    pmem_avail ");
355*6ecc4705SAndy Fiddaman 		memlist_dump(pci_bus_res[bus].pmem_avail);
356*6ecc4705SAndy Fiddaman 	}
357*6ecc4705SAndy Fiddaman }
35800dfdf4aSDana Myers 
35900dfdf4aSDana Myers /*ARGSUSED*/
36000dfdf4aSDana Myers static ACPI_STATUS
pci_process_acpi_device(ACPI_HANDLE hdl,UINT32 level,void * ctx,void ** rv)36100dfdf4aSDana Myers pci_process_acpi_device(ACPI_HANDLE hdl, UINT32 level, void *ctx, void **rv)
36200dfdf4aSDana Myers {
36300dfdf4aSDana Myers 	ACPI_DEVICE_INFO *adi;
364fbe8965dSDana Myers 	int		busnum;
36500dfdf4aSDana Myers 
36600dfdf4aSDana Myers 	/*
36700dfdf4aSDana Myers 	 * Use AcpiGetObjectInfo() to find the device _HID
36800dfdf4aSDana Myers 	 * If not a PCI root-bus, ignore this device and continue
36900dfdf4aSDana Myers 	 * the walk
37000dfdf4aSDana Myers 	 */
37157190917SDana Myers 	if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &adi)))
37200dfdf4aSDana Myers 		return (AE_OK);
37300dfdf4aSDana Myers 
37400dfdf4aSDana Myers 	if (!(adi->Valid & ACPI_VALID_HID)) {
37500dfdf4aSDana Myers 		AcpiOsFree(adi);
37600dfdf4aSDana Myers 		return (AE_OK);
37700dfdf4aSDana Myers 	}
37800dfdf4aSDana Myers 
37957190917SDana Myers 	if (strncmp(adi->HardwareId.String, PCI_ROOT_HID_STRING,
38000dfdf4aSDana Myers 	    sizeof (PCI_ROOT_HID_STRING)) &&
38157190917SDana Myers 	    strncmp(adi->HardwareId.String, PCI_EXPRESS_ROOT_HID_STRING,
38200dfdf4aSDana Myers 	    sizeof (PCI_EXPRESS_ROOT_HID_STRING))) {
38300dfdf4aSDana Myers 		AcpiOsFree(adi);
38400dfdf4aSDana Myers 		return (AE_OK);
38500dfdf4aSDana Myers 	}
38600dfdf4aSDana Myers 
38700dfdf4aSDana Myers 	AcpiOsFree(adi);
38800dfdf4aSDana Myers 
38900dfdf4aSDana Myers 	/*
3903349e36eSPaul Winder 	 * acpica_get_busno() will check the presence of _BBN and
3913349e36eSPaul Winder 	 * fail if not present. It will then use the _CRS method to
3923349e36eSPaul Winder 	 * retrieve the actual bus number assigned, it will fall back
3933349e36eSPaul Winder 	 * to _BBN should the _CRS method fail.
39400dfdf4aSDana Myers 	 */
3953349e36eSPaul Winder 	if (ACPI_SUCCESS(acpica_get_busno(hdl, &busnum))) {
396fbe8965dSDana Myers 		/*
397fbe8965dSDana Myers 		 * Ignore invalid _BBN return values here (rather
398fbe8965dSDana Myers 		 * than panic) and emit a warning; something else
399fbe8965dSDana Myers 		 * may suffer failure as a result of the broken BIOS.
400fbe8965dSDana Myers 		 */
401fbe8965dSDana Myers 		if ((busnum < 0) || (busnum > pci_bios_maxbus)) {
4021c21d439SDana Myers 			dcmn_err(CE_NOTE,
403*6ecc4705SAndy Fiddaman 			    "pci_process_acpi_device: invalid _BBN 0x%x",
404fbe8965dSDana Myers 			    busnum);
405fbe8965dSDana Myers 			return (AE_CTRL_DEPTH);
406fbe8965dSDana Myers 		}
407fbe8965dSDana Myers 
408fbe8965dSDana Myers 		/* PCI with valid _BBN */
409fbe8965dSDana Myers 		if (pci_bus_res[busnum].par_bus == (uchar_t)-1 &&
410fbe8965dSDana Myers 		    pci_bus_res[busnum].dip == NULL)
411fbe8965dSDana Myers 			create_root_bus_dip((uchar_t)busnum);
41200dfdf4aSDana Myers 		return (AE_CTRL_DEPTH);
41300dfdf4aSDana Myers 	}
41400dfdf4aSDana Myers 
41500dfdf4aSDana Myers 	/* PCI and no _BBN, continue walk */
41600dfdf4aSDana Myers 	return (AE_OK);
41700dfdf4aSDana Myers }
41800dfdf4aSDana Myers 
41900dfdf4aSDana Myers /*
42000dfdf4aSDana Myers  * Scan the ACPI namespace for all top-level instances of _BBN
42100dfdf4aSDana Myers  * in order to discover childless root-bridges (which enumeration
42200dfdf4aSDana Myers  * may not find; root-bridges are inferred by the existence of
42300dfdf4aSDana Myers  * children).  This scan should find all root-bridges that have
42400dfdf4aSDana Myers  * been enumerated, and any childless root-bridges not enumerated.
42500dfdf4aSDana Myers  * Root-bridge for bus 0 may not have a _BBN object.
42600dfdf4aSDana Myers  */
42700dfdf4aSDana Myers static void
pci_scan_bbn()42800dfdf4aSDana Myers pci_scan_bbn()
42900dfdf4aSDana Myers {
43000dfdf4aSDana Myers 	void *rv;
43100dfdf4aSDana Myers 
43200dfdf4aSDana Myers 	(void) AcpiGetDevices(NULL, pci_process_acpi_device, NULL, &rv);
43300dfdf4aSDana Myers }
43400dfdf4aSDana Myers 
43500dfdf4aSDana Myers static void
pci_unitaddr_cache_init(void)43600dfdf4aSDana Myers pci_unitaddr_cache_init(void)
43700dfdf4aSDana Myers {
43800dfdf4aSDana Myers 
43900dfdf4aSDana Myers 	puafd_handle = nvf_register_file(&pci_unitaddr_cache_ops);
44000dfdf4aSDana Myers 	ASSERT(puafd_handle);
44100dfdf4aSDana Myers 
44200dfdf4aSDana Myers 	list_create(nvf_list(puafd_handle), sizeof (pua_node_t),
44300dfdf4aSDana Myers 	    offsetof(pua_node_t, pua_nodes));
44400dfdf4aSDana Myers 
44500dfdf4aSDana Myers 	rw_enter(nvf_lock(puafd_handle), RW_WRITER);
44600dfdf4aSDana Myers 	(void) nvf_read_file(puafd_handle);
44700dfdf4aSDana Myers 	rw_exit(nvf_lock(puafd_handle));
44800dfdf4aSDana Myers }
44900dfdf4aSDana Myers 
45000dfdf4aSDana Myers /*
45100dfdf4aSDana Myers  * Format of /etc/devices/pci_unitaddr_persistent:
45200dfdf4aSDana Myers  *
45300dfdf4aSDana Myers  * The persistent record of unit-address assignments contains
45400dfdf4aSDana Myers  * a list of name/value pairs, where name is a string representation
45500dfdf4aSDana Myers  * of the "index value" of the PCI root-bus and the value is
45600dfdf4aSDana Myers  * the assigned unit-address.
45700dfdf4aSDana Myers  *
45800dfdf4aSDana Myers  * The "index value" is simply the zero-based index of the PCI
45900dfdf4aSDana Myers  * root-buses ordered by physical bus number; first PCI bus is 0,
46000dfdf4aSDana Myers  * second is 1, and so on.
46100dfdf4aSDana Myers  */
46200dfdf4aSDana Myers 
463e07545cfSDana Myers /*ARGSUSED*/
46400dfdf4aSDana Myers static int
pci_cache_unpack_nvlist(nvf_handle_t hdl,nvlist_t * nvl,char * name)46500dfdf4aSDana Myers pci_cache_unpack_nvlist(nvf_handle_t hdl, nvlist_t *nvl, char *name)
46600dfdf4aSDana Myers {
46700dfdf4aSDana Myers 	long		index;
46800dfdf4aSDana Myers 	int32_t		value;
46900dfdf4aSDana Myers 	nvpair_t	*np;
47000dfdf4aSDana Myers 	pua_node_t	*node;
47100dfdf4aSDana Myers 
47200dfdf4aSDana Myers 	np = NULL;
47300dfdf4aSDana Myers 	while ((np = nvlist_next_nvpair(nvl, np)) != NULL) {
47400dfdf4aSDana Myers 		/* name of nvpair is index value */
47500dfdf4aSDana Myers 		if (ddi_strtol(nvpair_name(np), NULL, 10, &index) != 0)
47600dfdf4aSDana Myers 			continue;
47700dfdf4aSDana Myers 
47800dfdf4aSDana Myers 		if (nvpair_value_int32(np, &value) != 0)
47900dfdf4aSDana Myers 			continue;
48000dfdf4aSDana Myers 
48100dfdf4aSDana Myers 		node = kmem_zalloc(sizeof (pua_node_t), KM_SLEEP);
48200dfdf4aSDana Myers 		node->pua_index = index;
48300dfdf4aSDana Myers 		node->pua_addr = value;
48400dfdf4aSDana Myers 		list_insert_tail(nvf_list(hdl), node);
48500dfdf4aSDana Myers 	}
48600dfdf4aSDana Myers 
48700dfdf4aSDana Myers 	pua_cache_valid = 1;
48800dfdf4aSDana Myers 	return (DDI_SUCCESS);
48900dfdf4aSDana Myers }
49000dfdf4aSDana Myers 
49100dfdf4aSDana Myers static int
pci_cache_pack_nvlist(nvf_handle_t hdl,nvlist_t ** ret_nvl)49200dfdf4aSDana Myers pci_cache_pack_nvlist(nvf_handle_t hdl, nvlist_t **ret_nvl)
49300dfdf4aSDana Myers {
49400dfdf4aSDana Myers 	int		rval;
49500dfdf4aSDana Myers 	nvlist_t	*nvl, *sub_nvl;
49600dfdf4aSDana Myers 	list_t		*listp;
49700dfdf4aSDana Myers 	pua_node_t	*pua;
49800dfdf4aSDana Myers 	char		buf[13];
49900dfdf4aSDana Myers 
50000dfdf4aSDana Myers 	ASSERT(RW_WRITE_HELD(nvf_lock(hdl)));
50100dfdf4aSDana Myers 
50200dfdf4aSDana Myers 	rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
50300dfdf4aSDana Myers 	if (rval != DDI_SUCCESS) {
50400dfdf4aSDana Myers 		nvf_error("%s: nvlist alloc error %d\n",
50500dfdf4aSDana Myers 		    nvf_cache_name(hdl), rval);
50600dfdf4aSDana Myers 		return (DDI_FAILURE);
50700dfdf4aSDana Myers 	}
50800dfdf4aSDana Myers 
50900dfdf4aSDana Myers 	sub_nvl = NULL;
51000dfdf4aSDana Myers 	rval = nvlist_alloc(&sub_nvl, NV_UNIQUE_NAME, KM_SLEEP);
51100dfdf4aSDana Myers 	if (rval != DDI_SUCCESS)
51200dfdf4aSDana Myers 		goto error;
51300dfdf4aSDana Myers 
51400dfdf4aSDana Myers 	listp = nvf_list(hdl);
51500dfdf4aSDana Myers 	for (pua = list_head(listp); pua != NULL;
51600dfdf4aSDana Myers 	    pua = list_next(listp, pua)) {
517e07545cfSDana Myers 		(void) snprintf(buf, sizeof (buf), "%d", pua->pua_index);
51800dfdf4aSDana Myers 		rval = nvlist_add_int32(sub_nvl, buf, pua->pua_addr);
51900dfdf4aSDana Myers 		if (rval != DDI_SUCCESS)
52000dfdf4aSDana Myers 			goto error;
52100dfdf4aSDana Myers 	}
52200dfdf4aSDana Myers 
52300dfdf4aSDana Myers 	rval = nvlist_add_nvlist(nvl, "table", sub_nvl);
52400dfdf4aSDana Myers 	if (rval != DDI_SUCCESS)
52500dfdf4aSDana Myers 		goto error;
52600dfdf4aSDana Myers 	nvlist_free(sub_nvl);
52700dfdf4aSDana Myers 
52800dfdf4aSDana Myers 	*ret_nvl = nvl;
52900dfdf4aSDana Myers 	return (DDI_SUCCESS);
53000dfdf4aSDana Myers 
53100dfdf4aSDana Myers error:
532aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(sub_nvl);
53300dfdf4aSDana Myers 	ASSERT(nvl);
53400dfdf4aSDana Myers 	nvlist_free(nvl);
53500dfdf4aSDana Myers 	*ret_nvl = NULL;
53600dfdf4aSDana Myers 	return (DDI_FAILURE);
53700dfdf4aSDana Myers }
53800dfdf4aSDana Myers 
53900dfdf4aSDana Myers static void
pci_cache_free_list(nvf_handle_t hdl)54000dfdf4aSDana Myers pci_cache_free_list(nvf_handle_t hdl)
54100dfdf4aSDana Myers {
54200dfdf4aSDana Myers 	list_t		*listp;
54300dfdf4aSDana Myers 	pua_node_t	*pua;
54400dfdf4aSDana Myers 
54500dfdf4aSDana Myers 	ASSERT(RW_WRITE_HELD(nvf_lock(hdl)));
54600dfdf4aSDana Myers 
54700dfdf4aSDana Myers 	listp = nvf_list(hdl);
54800dfdf4aSDana Myers 	for (pua = list_head(listp); pua != NULL;
54900dfdf4aSDana Myers 	    pua = list_next(listp, pua)) {
55000dfdf4aSDana Myers 		list_remove(listp, pua);
55100dfdf4aSDana Myers 		kmem_free(pua, sizeof (pua_node_t));
55200dfdf4aSDana Myers 	}
55300dfdf4aSDana Myers }
55400dfdf4aSDana Myers 
55500dfdf4aSDana Myers 
55600dfdf4aSDana Myers static int
pci_unitaddr_cache_valid(void)55700dfdf4aSDana Myers pci_unitaddr_cache_valid(void)
55800dfdf4aSDana Myers {
55900dfdf4aSDana Myers 
56000dfdf4aSDana Myers 	/* read only, no need for rw lock */
56100dfdf4aSDana Myers 	return (pua_cache_valid);
56200dfdf4aSDana Myers }
56300dfdf4aSDana Myers 
56400dfdf4aSDana Myers 
56500dfdf4aSDana Myers static int
pci_bus_unitaddr(int index)56600dfdf4aSDana Myers pci_bus_unitaddr(int index)
56700dfdf4aSDana Myers {
56800dfdf4aSDana Myers 	pua_node_t	*pua;
56900dfdf4aSDana Myers 	list_t		*listp;
57000dfdf4aSDana Myers 	int		addr;
57100dfdf4aSDana Myers 
57200dfdf4aSDana Myers 	rw_enter(nvf_lock(puafd_handle), RW_READER);
57300dfdf4aSDana Myers 
57400dfdf4aSDana Myers 	addr = -1;	/* default return if no match */
57500dfdf4aSDana Myers 	listp = nvf_list(puafd_handle);
57600dfdf4aSDana Myers 	for (pua = list_head(listp); pua != NULL;
57700dfdf4aSDana Myers 	    pua = list_next(listp, pua)) {
57800dfdf4aSDana Myers 		if (pua->pua_index == index) {
57900dfdf4aSDana Myers 			addr = pua->pua_addr;
58000dfdf4aSDana Myers 			break;
58100dfdf4aSDana Myers 		}
58200dfdf4aSDana Myers 	}
58300dfdf4aSDana Myers 
58400dfdf4aSDana Myers 	rw_exit(nvf_lock(puafd_handle));
58500dfdf4aSDana Myers 	return (addr);
58600dfdf4aSDana Myers }
58700dfdf4aSDana Myers 
58800dfdf4aSDana Myers static void
pci_unitaddr_cache_create(void)58900dfdf4aSDana Myers pci_unitaddr_cache_create(void)
59000dfdf4aSDana Myers {
59100dfdf4aSDana Myers 	int		i, index;
59200dfdf4aSDana Myers 	pua_node_t	*node;
59300dfdf4aSDana Myers 	list_t		*listp;
59400dfdf4aSDana Myers 
59500dfdf4aSDana Myers 	rw_enter(nvf_lock(puafd_handle), RW_WRITER);
59600dfdf4aSDana Myers 
59700dfdf4aSDana Myers 	index = 0;
59800dfdf4aSDana Myers 	listp = nvf_list(puafd_handle);
59947310cedSDana Myers 	for (i = 0; i <= pci_bios_maxbus; i++) {
60000dfdf4aSDana Myers 		/* skip non-root (peer) PCI busses */
60100dfdf4aSDana Myers 		if ((pci_bus_res[i].par_bus != (uchar_t)-1) ||
60200dfdf4aSDana Myers 		    (pci_bus_res[i].dip == NULL))
60300dfdf4aSDana Myers 			continue;
60400dfdf4aSDana Myers 		node = kmem_zalloc(sizeof (pua_node_t), KM_SLEEP);
60500dfdf4aSDana Myers 		node->pua_index = index++;
60600dfdf4aSDana Myers 		node->pua_addr = pci_bus_res[i].root_addr;
60700dfdf4aSDana Myers 		list_insert_tail(listp, node);
60800dfdf4aSDana Myers 	}
60900dfdf4aSDana Myers 
61000dfdf4aSDana Myers 	(void) nvf_mark_dirty(puafd_handle);
61100dfdf4aSDana Myers 	rw_exit(nvf_lock(puafd_handle));
61200dfdf4aSDana Myers 	nvf_wake_daemon();
61300dfdf4aSDana Myers }
61400dfdf4aSDana Myers 
61500dfdf4aSDana Myers 
6167c478bd9Sstevel@tonic-gate /*
6177c478bd9Sstevel@tonic-gate  * Enumerate all PCI devices
6187c478bd9Sstevel@tonic-gate  */
6197c478bd9Sstevel@tonic-gate void
pci_setup_tree(void)62000dfdf4aSDana Myers pci_setup_tree(void)
6217c478bd9Sstevel@tonic-gate {
62205043691Sjames north - Sun Microsystems - Austin United States 	uint_t i, root_bus_addr = 0;
624f55ce205Sszhou 	alloc_res_array();
62547310cedSDana Myers 	for (i = 0; i <= pci_bios_maxbus; i++) {
6267c478bd9Sstevel@tonic-gate 		pci_bus_res[i].par_bus = (uchar_t)-1;
6277c478bd9Sstevel@tonic-gate 		pci_bus_res[i].root_addr = (uchar_t)-1;
6287c478bd9Sstevel@tonic-gate 		pci_bus_res[i].sub_bus = i;
6297c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 	pci_bus_res[0].root_addr = root_bus_addr++;
6327c478bd9Sstevel@tonic-gate 	create_root_bus_dip(0);
6337c478bd9Sstevel@tonic-gate 	enumerate_bus_devs(0, CONFIG_INFO);
6357c478bd9Sstevel@tonic-gate 	/*
6367c478bd9Sstevel@tonic-gate 	 * Now enumerate peer busses
6377c478bd9Sstevel@tonic-gate 	 *
63847310cedSDana Myers 	 * We loop till pci_bios_maxbus. On most systems, there is
6397c478bd9Sstevel@tonic-gate 	 * one more bus at the high end, which implements the ISA
6407c478bd9Sstevel@tonic-gate 	 * compatibility bus. We don't care about that.
6417c478bd9Sstevel@tonic-gate 	 *
6427c478bd9Sstevel@tonic-gate 	 * Note: In the old (bootconf) enumeration, the peer bus
6437c478bd9Sstevel@tonic-gate 	 *	address did not use the bus number, and there were
6447c478bd9Sstevel@tonic-gate 	 *	too many peer busses created. The root_bus_addr is
6457c478bd9Sstevel@tonic-gate 	 *	used to maintain the old peer bus address assignment.
6467c478bd9Sstevel@tonic-gate 	 *	However, we stop enumerating phantom peers with no
6477c478bd9Sstevel@tonic-gate 	 *	device below.
6487c478bd9Sstevel@tonic-gate 	 */
64947310cedSDana Myers 	for (i = 1; i <= pci_bios_maxbus; i++) {
6507c478bd9Sstevel@tonic-gate 		if (pci_bus_res[i].dip == NULL) {
6517c478bd9Sstevel@tonic-gate 			pci_bus_res[i].root_addr = root_bus_addr++;
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 		enumerate_bus_devs(i, CONFIG_INFO);
655b1f176e8Sjg 		/* add slot-names property for named pci hot-plug slots */
656b1f176e8Sjg 		add_bus_slot_names_prop(i);
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate }
66025145214Smyers /*
66125145214Smyers  * >0 = present, 0 = not present, <0 = error
66225145214Smyers  */
66325145214Smyers static int
pci_bbn_present(int bus)66425145214Smyers pci_bbn_present(int bus)
66525145214Smyers {
66625145214Smyers 	ACPI_HANDLE	hdl;
66725145214Smyers 	int	rv;
66925145214Smyers 	/* no dip means no _BBN */
67025145214Smyers 	if (pci_bus_res[bus].dip == NULL)
67125145214Smyers 		return (0);
673db2bae30SDana Myers 	rv = -1;	/* default return value in case of error below */
674db2bae30SDana Myers 	if (ACPI_SUCCESS(acpica_get_handle(pci_bus_res[bus].dip, &hdl))) {
675db2bae30SDana Myers 		switch (AcpiEvaluateObject(hdl, "_BBN", NULL, NULL)) {
676db2bae30SDana Myers 		case AE_OK:
677db2bae30SDana Myers 			rv = 1;
678db2bae30SDana Myers 			break;
679db2bae30SDana Myers 		case AE_NOT_FOUND:
680db2bae30SDana Myers 			rv = 0;
681db2bae30SDana Myers 			break;
682db2bae30SDana Myers 		default:
683db2bae30SDana Myers 			break;
684db2bae30SDana Myers 		}
685db2bae30SDana Myers 	}
687db2bae30SDana Myers 	return (rv);
68825145214Smyers }
69025145214Smyers /*
69125145214Smyers  * Return non-zero if any PCI bus in the system has an associated
69225145214Smyers  * _BBN object, 0 otherwise.
69325145214Smyers  */
69425145214Smyers static int
pci_roots_have_bbn(void)69525145214Smyers pci_roots_have_bbn(void)
69625145214Smyers {
69725145214Smyers 	int	i;
69925145214Smyers 	/*
70025145214Smyers 	 * Scan the PCI busses and look for at least 1 _BBN
70125145214Smyers 	 */
70247310cedSDana Myers 	for (i = 0; i <= pci_bios_maxbus; i++) {
70325145214Smyers 		/* skip non-root (peer) PCI busses */
70425145214Smyers 		if (pci_bus_res[i].par_bus != (uchar_t)-1)
70525145214Smyers 			continue;
70725145214Smyers 		if (pci_bbn_present(i) > 0)
70825145214Smyers 			return (1);
70925145214Smyers 	}
71025145214Smyers 	return (0);
71225145214Smyers }
71425145214Smyers /*
71525145214Smyers  * return non-zero if the machine is one on which we renumber
71625145214Smyers  * the internal pci unit-addresses
71725145214Smyers  */
71825145214Smyers static int
pci_bus_renumber()71925145214Smyers pci_bus_renumber()
72025145214Smyers {
721ee8c1d4aSdm 	ACPI_TABLE_HEADER *fadt;
723ee8c1d4aSdm 	if (pci_bus_always_renumber)
72425145214Smyers 		return (1);
726ee8c1d4aSdm 	/* get the FADT */
727db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
728db2bae30SDana Myers 	    AE_OK)
72925145214Smyers 		return (0);
731ee8c1d4aSdm 	/* compare OEM Table ID to "SUNm31" */
732ee8c1d4aSdm 	if (strncmp("SUNm31", fadt->OemId, 6))
733ee8c1d4aSdm 		return (0);
734ee8c1d4aSdm 	else
735ee8c1d4aSdm 		return (1);
73625145214Smyers }
73825145214Smyers /*
73925145214Smyers  * Initial enumeration of the physical PCI bus hierarchy can
74025145214Smyers  * leave 'gaps' in the order of peer PCI bus unit-addresses.
74125145214Smyers  * Systems with more than one peer PCI bus *must* have an ACPI
74225145214Smyers  * _BBN object associated with each peer bus; use the presence
74325145214Smyers  * of this object to remove gaps in the numbering of the peer
74425145214Smyers  * PCI bus unit-addresses - only peer busses with an associated
74525145214Smyers  * _BBN are counted.
74625145214Smyers  */
74725145214Smyers static void
pci_renumber_root_busses(void)74825145214Smyers pci_renumber_root_busses(void)
74925145214Smyers {
75025145214Smyers 	int pci_regs[] = {0, 0, 0};
75125145214Smyers 	int	i, root_addr = 0;
753ee8c1d4aSdm 	/*
754ee8c1d4aSdm 	 * Currently, we only enable the re-numbering on specific
755ee8c1d4aSdm 	 * Sun machines; this is a work-around for the more complicated
756ee8c1d4aSdm 	 * issue of upgrade changing physical device paths
757ee8c1d4aSdm 	 */
75825145214Smyers 	if (!pci_bus_renumber())
75925145214Smyers 		return;
76125145214Smyers 	/*
76225145214Smyers 	 * If we find no _BBN objects at all, we either don't need
76325145214Smyers 	 * to do anything or can't do anything anyway
76425145214Smyers 	 */
76525145214Smyers 	if (!pci_roots_have_bbn())
76625145214Smyers 		return;
76847310cedSDana Myers 	for (i = 0; i <= pci_bios_maxbus; i++) {
76925145214Smyers 		/* skip non-root (peer) PCI busses */
77025145214Smyers 		if (pci_bus_res[i].par_bus != (uchar_t)-1)
77125145214Smyers 			continue;
77325145214Smyers 		if (pci_bbn_present(i) < 1) {
77425145214Smyers 			pci_bus_res[i].root_addr = (uchar_t)-1;
77525145214Smyers 			continue;
77625145214Smyers 		}
77825145214Smyers 		ASSERT(pci_bus_res[i].dip != NULL);
77925145214Smyers 		if (pci_bus_res[i].root_addr != root_addr) {
78025145214Smyers 			/* update reg property for node */
78125145214Smyers 			pci_bus_res[i].root_addr = root_addr;
78225145214Smyers 			pci_regs[0] = pci_bus_res[i].root_addr;
78325145214Smyers 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
78425145214Smyers 			    pci_bus_res[i].dip, "reg", (int *)pci_regs, 3);
78525145214Smyers 		}
78625145214Smyers 		root_addr++;
78725145214Smyers 	}
78825145214Smyers }
79078323854SJudy Chen void
pci_register_isa_resources(int type,uint32_t base,uint32_t size)7911d6b7b34SJudy Chen pci_register_isa_resources(int type, uint32_t base, uint32_t size)
792aaba6dfeSmyers {
7931d6b7b34SJudy Chen 	(void) memlist_insert(
7942f283da5SDan Mick 	    (type == 1) ?  &isa_res.io_used : &isa_res.mem_used,
7951d6b7b34SJudy Chen 	    base, size);
796aaba6dfeSmyers }
7985af4ae46Sjveta /*
79905f867c3Sgs  * Remove the resources which are already used by devices under a subtractive
80005f867c3Sgs  * bridge from the bus's resources lists, because they're not available, and
80105f867c3Sgs  * shouldn't be allocated to other buses.  This is necessary because tracking
80205f867c3Sgs  * resources for subtractive bridges is not complete.  (Subtractive bridges only
80305f867c3Sgs  * track some of their claimed resources, not "the rest of the address space" as
80405f867c3Sgs  * they should, so that allocation to peer non-subtractive PPBs is easier.  We
80505f867c3Sgs  * need a fully-capable global resource allocator).
8065af4ae46Sjveta  */
80705f867c3Sgs static void
remove_subtractive_res()80805f867c3Sgs remove_subtractive_res()
8095af4ae46Sjveta {
81005f867c3Sgs 	int i, j;
81105f867c3Sgs 	struct memlist *list;
81347310cedSDana Myers 	for (i = 0; i <= pci_bios_maxbus; i++) {
81405f867c3Sgs 		if (pci_bus_res[i].subtractive) {
81505f867c3Sgs 			/* remove used io ports */
8162f283da5SDan Mick 			list = pci_bus_res[i].io_used;
81705f867c3Sgs 			while (list) {
81847310cedSDana Myers 				for (j = 0; j <= pci_bios_maxbus; j++)
8198fc7923fSDana Myers 					(void) memlist_remove(
8202f283da5SDan Mick 					    &pci_bus_res[j].io_avail,
82156f33205SJonathan Adams 					    list->ml_address, list->ml_size);
82256f33205SJonathan Adams 				list = list->ml_next;
82305f867c3Sgs 			}
82405f867c3Sgs 			/* remove used mem resource */
8252f283da5SDan Mick 			list = pci_bus_res[i].mem_used;
82605f867c3Sgs 			while (list) {
82747310cedSDana Myers 				for (j = 0; j <= pci_bios_maxbus; j++) {
8288fc7923fSDana Myers 					(void) memlist_remove(
8292f283da5SDan Mick 					    &pci_bus_res[j].mem_avail,
83056f33205SJonathan Adams 					    list->ml_address, list->ml_size);
8318fc7923fSDana Myers 					(void) memlist_remove(
8322f283da5SDan Mick 					    &pci_bus_res[j].pmem_avail,
83356f33205SJonathan Adams 					    list->ml_address, list->ml_size);
83405f867c3Sgs 				}
83556f33205SJonathan Adams 				list = list->ml_next;
83605f867c3Sgs 			}
83705f867c3Sgs 			/* remove used prefetchable mem resource */
8382f283da5SDan Mick 			list = pci_bus_res[i].pmem_used;
83905f867c3Sgs 			while (list) {
84047310cedSDana Myers 				for (j = 0; j <= pci_bios_maxbus; j++) {
8418fc7923fSDana Myers 					(void) memlist_remove(
8422f283da5SDan Mick 					    &pci_bus_res[j].pmem_avail,
84356f33205SJonathan Adams 					    list->ml_address, list->ml_size);
8448fc7923fSDana Myers 					(void) memlist_remove(
8452f283da5SDan Mick 					    &pci_bus_res[j].mem_avail,
84656f33205SJonathan Adams 					    list->ml_address, list->ml_size);
84705f867c3Sgs 				}
84856f33205SJonathan Adams 				list = list->ml_next;
84905f867c3Sgs 			}
8505af4ae46Sjveta 		}
85105f867c3Sgs 	}
85205f867c3Sgs }
8548fc7923fSDana Myers /*
8552f283da5SDan Mick  * Set up (or complete the setup of) the bus_avail resource list
8568fc7923fSDana Myers  */
85705f867c3Sgs static void
setup_bus_res(int bus)85805f867c3Sgs setup_bus_res(int bus)
85905f867c3Sgs {
86005f867c3Sgs 	uchar_t par_bus;
86205f867c3Sgs 	if (pci_bus_res[bus].dip == NULL)	/* unused bus */
86305f867c3Sgs 		return;
8658fc7923fSDana Myers 	/*
8662f283da5SDan Mick 	 * Set up bus_avail if not already filled in by populate_bus_res()
8678fc7923fSDana Myers 	 */
8682f283da5SDan Mick 	if (pci_bus_res[bus].bus_avail == NULL) {
8698fc7923fSDana Myers 		ASSERT(pci_bus_res[bus].sub_bus >= bus);
8702f283da5SDan Mick 		memlist_insert(&pci_bus_res[bus].bus_avail, bus,
8718fc7923fSDana Myers 		    pci_bus_res[bus].sub_bus - bus + 1);
87205f867c3Sgs 	}
8742f283da5SDan Mick 	ASSERT(pci_bus_res[bus].bus_avail != NULL);
8758fc7923fSDana Myers 
87605f867c3Sgs 	/*
87705f867c3Sgs 	 * Remove resources from parent bus node if this is not a
87805f867c3Sgs 	 * root bus.
87905f867c3Sgs 	 */
88005f867c3Sgs 	par_bus = pci_bus_res[bus].par_bus;
88105f867c3Sgs 	if (par_bus != (uchar_t)-1) {
8822f283da5SDan Mick 		ASSERT(pci_bus_res[par_bus].bus_avail != NULL);
8832f283da5SDan Mick 		memlist_remove_list(&pci_bus_res[par_bus].bus_avail,
8842f283da5SDan Mick 		    pci_bus_res[bus].bus_avail);
88505f867c3Sgs 	}
8868fc7923fSDana Myers 
8872f283da5SDan Mick 	/* remove self from bus_avail */;
8882f283da5SDan Mick 	(void) memlist_remove(&pci_bus_res[bus].bus_avail, bus, 1);
8895af4ae46Sjveta }
891*6ecc4705SAndy Fiddaman /*
892*6ecc4705SAndy Fiddaman  * Allocate a resource from the parent bus
893*6ecc4705SAndy Fiddaman  */
89405f867c3Sgs static uint64_t
get_parbus_res(uchar_t parbus,uchar_t bus,uint64_t size,uint64_t align,enum parbus_mem mem)895*6ecc4705SAndy Fiddaman get_parbus_res(uchar_t parbus, uchar_t bus, uint64_t size, uint64_t align,
896*6ecc4705SAndy Fiddaman     enum parbus_mem mem)
8975af4ae46Sjveta {
89805f867c3Sgs 	uint64_t addr = 0;
89905f867c3Sgs 	uchar_t res_bus;
90105f867c3Sgs 	/*
9028fc7923fSDana Myers 	 * Skip root(peer) buses in multiple-root-bus systems when
903*6ecc4705SAndy Fiddaman 	 * ACPI resource discovery was not successfully done; the
904*6ecc4705SAndy Fiddaman 	 * initial resources set on each root bus might not be correctly
905*6ecc4705SAndy Fiddaman 	 * accounted for in this case.
90605f867c3Sgs 	 */
90705f867c3Sgs 	if ((