xref: /illumos-gate/usr/src/uts/intel/io/pci/pci_boot.c (revision 05f867c3)
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 /*
22*05f867c3Sgs  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/stat.h>
307c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
317c478bd9Sstevel@tonic-gate #include <sys/pci.h>
327c478bd9Sstevel@tonic-gate #include <sys/pci_impl.h>
337c478bd9Sstevel@tonic-gate #include <sys/pci_cfgspace.h>
347c478bd9Sstevel@tonic-gate #include <sys/memlist.h>
357c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
3670025d76Sjohnny #include <io/pci/mps_table.h>
37c88420b3Sdmick #include <sys/pci_cfgspace.h>
38c88420b3Sdmick #include <sys/pci_cfgspace_impl.h>
39c88420b3Sdmick #include <sys/psw.h>
4009f67678Sanish #include "../../../../common/pci/pci_strings.h"
41c8589f13Ssethg #include <sys/apic.h>
428a5a0d1eSanish #include <io/pciex/pcie_nvidia.h>
435af4ae46Sjveta #include <io/hotplug/pciehpc/pciehpc_acpi.h>
4425145214Smyers #include <sys/acpi/acpi.h>
4525145214Smyers #include <sys/acpica.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	pci_getb	(*pci_getb_func)
487c478bd9Sstevel@tonic-gate #define	pci_getw	(*pci_getw_func)
497c478bd9Sstevel@tonic-gate #define	pci_getl	(*pci_getl_func)
507c478bd9Sstevel@tonic-gate #define	pci_putb	(*pci_putb_func)
517c478bd9Sstevel@tonic-gate #define	pci_putw	(*pci_putw_func)
527c478bd9Sstevel@tonic-gate #define	pci_putl	(*pci_putl_func)
537c478bd9Sstevel@tonic-gate #define	dcmn_err	if (pci_boot_debug) cmn_err
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #define	CONFIG_INFO	0
567c478bd9Sstevel@tonic-gate #define	CONFIG_UPDATE	1
577c478bd9Sstevel@tonic-gate #define	CONFIG_NEW	2
58bd87be88Ssethg #define	CONFIG_FIX	3
5970025d76Sjohnny #define	COMPAT_BUFSIZE	512
607c478bd9Sstevel@tonic-gate 
61*05f867c3Sgs #define	PPB_IO_ALIGNMENT	0x1000		/* 4K aligned */
62*05f867c3Sgs #define	PPB_MEM_ALIGNMENT	0x100000	/* 1M aligned */
63*05f867c3Sgs 
64bd87be88Ssethg /* See AMD-8111 Datasheet Rev 3.03, Page 149: */
65bd87be88Ssethg #define	LPC_IO_CONTROL_REG_1	0x40
66bd87be88Ssethg #define	AMD8111_ENABLENMI	(uint8_t)0x80
67bd87be88Ssethg #define	DEVID_AMD8111_LPC	0x7468
68bd87be88Ssethg 
69bd87be88Ssethg struct pci_fixundo {
70bd87be88Ssethg 	uint8_t			bus;
71bd87be88Ssethg 	uint8_t			dev;
72bd87be88Ssethg 	uint8_t			fn;
73bd87be88Ssethg 	void			(*undofn)(uint8_t, uint8_t, uint8_t);
74bd87be88Ssethg 	struct pci_fixundo	*next;
75bd87be88Ssethg };
76bd87be88Ssethg 
77*05f867c3Sgs struct pci_devfunc {
78*05f867c3Sgs 	struct pci_devfunc *next;
79*05f867c3Sgs 	dev_info_t *dip;
80*05f867c3Sgs 	uchar_t dev;
81*05f867c3Sgs 	uchar_t func;
82*05f867c3Sgs 	boolean_t reprogram;	/* this device needs to be reprogrammed */
83*05f867c3Sgs };
84*05f867c3Sgs 
857c478bd9Sstevel@tonic-gate extern int pci_bios_nbus;
867c478bd9Sstevel@tonic-gate static uchar_t max_dev_pci = 32;	/* PCI standard */
877c478bd9Sstevel@tonic-gate int pci_boot_debug = 0;
887c478bd9Sstevel@tonic-gate extern struct memlist *find_bus_res(int, int);
89bd87be88Ssethg static struct pci_fixundo *undolist = NULL;
90*05f867c3Sgs static int num_root_bus = 0;	/* count of root buses */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Module prototypes
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate static void enumerate_bus_devs(uchar_t bus, int config_op);
967c478bd9Sstevel@tonic-gate static void create_root_bus_dip(uchar_t bus);
97*05f867c3Sgs static void process_devfunc(uchar_t, uchar_t, uchar_t, uchar_t,
987c478bd9Sstevel@tonic-gate     ushort_t, int);
997c478bd9Sstevel@tonic-gate static void add_compatible(dev_info_t *, ushort_t, ushort_t,
10070025d76Sjohnny     ushort_t, ushort_t, uchar_t, uint_t, int);
1017c478bd9Sstevel@tonic-gate static int add_reg_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int, int);
10270025d76Sjohnny static void add_ppb_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int);
1037c478bd9Sstevel@tonic-gate static void add_model_prop(dev_info_t *, uint_t);
1047c478bd9Sstevel@tonic-gate static void add_bus_range_prop(int);
105b1f176e8Sjg static void add_bus_slot_names_prop(int);
1067c478bd9Sstevel@tonic-gate static void add_ppb_ranges_prop(int);
1077c478bd9Sstevel@tonic-gate static void add_bus_available_prop(int);
108*05f867c3Sgs static void fix_ppb_res(uchar_t, boolean_t);
109f55ce205Sszhou static void alloc_res_array();
110c8589f13Ssethg static void create_ioapic_node(int bus, int dev, int fn, ushort_t vendorid,
111c8589f13Ssethg     ushort_t deviceid);
112d57b3b3dSprasad static void pciex_slot_names_prop(dev_info_t *, ushort_t);
1137c478bd9Sstevel@tonic-gate 
11475bcd456Sjg extern int pci_slot_names_prop(int, char *, int);
11575bcd456Sjg 
116ee8c1d4aSdm /* set non-zero to force PCI peer-bus renumbering */
11725145214Smyers int pci_bus_always_renumber = 0;
11825145214Smyers 
119fc396574Srw /* get the subordinate bus # for a root/peer bus */
120fc396574Srw static int
121fc396574Srw pci_root_subbus(int bus, uchar_t *subbus)
122fc396574Srw {
123fc396574Srw 	ACPI_HANDLE	hdl;
124fc396574Srw 	ACPI_BUFFER	rb;
125fc396574Srw 	ACPI_RESOURCE	*rp;
126fc396574Srw 	int	rv;
127fc396574Srw 
128fc396574Srw 	if (pci_bus_res[bus].dip == NULL) {
129fc396574Srw 		/* non-used bus # */
130fc396574Srw 		return (AE_ERROR);
131fc396574Srw 	}
1325cff7825Smh 	if (acpica_get_handle(pci_bus_res[bus].dip, &hdl) != AE_OK) {
133fc396574Srw 		cmn_err(CE_WARN, "!No ACPI obj for bus%d, ACPI OFF?\n", bus);
134fc396574Srw 		return (AE_ERROR);
135fc396574Srw 	}
136fc396574Srw 
137fc396574Srw 	rb.Length = ACPI_ALLOCATE_BUFFER;
138fc396574Srw 	if (AcpiGetCurrentResources(hdl, &rb) != AE_OK) {
139fc396574Srw 		cmn_err(CE_WARN, "!_CRS failed on pci%d\n", bus);
140fc396574Srw 		return (AE_ERROR);
141fc396574Srw 	}
142fc396574Srw 
143fc396574Srw 	rv = AE_ERROR;
144fc396574Srw 
145fc396574Srw 	for (rp = rb.Pointer; rp->Type != ACPI_RESOURCE_TYPE_END_TAG;
146fc396574Srw 	    rp = ACPI_NEXT_RESOURCE(rp)) {
147fc396574Srw 
148fc396574Srw 		switch (rp->Type) {
1499896aa55Sjveta 		case ACPI_RESOURCE_TYPE_ADDRESS16:
1509896aa55Sjveta 			if (rp->Data.Address.ResourceType !=
1519896aa55Sjveta 			    ACPI_BUS_NUMBER_RANGE)
1529896aa55Sjveta 				continue;
1539896aa55Sjveta 			*subbus = (uchar_t)rp->Data.Address16.Maximum;
1549896aa55Sjveta 			dcmn_err(CE_NOTE, "Address16,subbus=%d\n", *subbus);
1559896aa55Sjveta 			break;
1569896aa55Sjveta 		case ACPI_RESOURCE_TYPE_ADDRESS32:
1579896aa55Sjveta 			if (rp->Data.Address.ResourceType !=
1589896aa55Sjveta 			    ACPI_BUS_NUMBER_RANGE)
1599896aa55Sjveta 				continue;
1609896aa55Sjveta 			*subbus = (uchar_t)rp->Data.Address32.Maximum;
1619896aa55Sjveta 			dcmn_err(CE_NOTE, "Address32,subbus=%d\n", *subbus);
1629896aa55Sjveta 			break;
1639896aa55Sjveta 		case ACPI_RESOURCE_TYPE_ADDRESS64:
1649896aa55Sjveta 			if (rp->Data.Address.ResourceType !=
1659896aa55Sjveta 			    ACPI_BUS_NUMBER_RANGE)
1669896aa55Sjveta 				continue;
1679896aa55Sjveta 			*subbus = (uchar_t)rp->Data.Address64.Maximum;
1689896aa55Sjveta 			dcmn_err(CE_NOTE, "Address64,subbus=%d\n", *subbus);
1699896aa55Sjveta 			break;
1709896aa55Sjveta 		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
1719896aa55Sjveta 			if (rp->Data.Address.ResourceType !=
1729896aa55Sjveta 			    ACPI_BUS_NUMBER_RANGE)
1739896aa55Sjveta 				continue;
1749896aa55Sjveta 			*subbus = (uchar_t)rp->Data.ExtAddress64.Maximum;
1759896aa55Sjveta 			dcmn_err(CE_NOTE, "ExtAdr64,subbus=%d\n", *subbus);
1769896aa55Sjveta 			break;
1779896aa55Sjveta 		default:
1789896aa55Sjveta 			dcmn_err(CE_NOTE, "rp->Type=%d\n", rp->Type);
1799896aa55Sjveta 			continue;
180fc396574Srw 		}
181fc396574Srw 
182fc396574Srw 		/* found the bus-range resource */
183fc396574Srw 		dcmn_err(CE_NOTE, "pci%d, subbus=%d\n", bus, *subbus);
184fc396574Srw 		rv = AE_OK;
185fc396574Srw 
186fc396574Srw 		/* This breaks out of the resource scanning loop */
187fc396574Srw 		break;
188fc396574Srw 	}
189fc396574Srw 
190fc396574Srw 	AcpiOsFree(rb.Pointer);
191fc396574Srw 	if (rv != AE_OK)
192fc396574Srw 		cmn_err(CE_NOTE, "!No bus-range resource for pci%d\n", bus);
193fc396574Srw 
194fc396574Srw 	return (rv);
195fc396574Srw 
196fc396574Srw }
197fc396574Srw 
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate  * Enumerate all PCI devices
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate void
2027c478bd9Sstevel@tonic-gate pci_setup_tree()
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	uchar_t i, root_bus_addr = 0;
2057c478bd9Sstevel@tonic-gate 
206f55ce205Sszhou 	alloc_res_array();
2077c478bd9Sstevel@tonic-gate 	for (i = 0; i <= pci_bios_nbus; i++) {
2087c478bd9Sstevel@tonic-gate 		pci_bus_res[i].par_bus = (uchar_t)-1;
2097c478bd9Sstevel@tonic-gate 		pci_bus_res[i].root_addr = (uchar_t)-1;
2107c478bd9Sstevel@tonic-gate 		pci_bus_res[i].sub_bus = i;
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	pci_bus_res[0].root_addr = root_bus_addr++;
2147c478bd9Sstevel@tonic-gate 	create_root_bus_dip(0);
2157c478bd9Sstevel@tonic-gate 	enumerate_bus_devs(0, CONFIG_INFO);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/*
2187c478bd9Sstevel@tonic-gate 	 * Now enumerate peer busses
2197c478bd9Sstevel@tonic-gate 	 *
2207c478bd9Sstevel@tonic-gate 	 * We loop till pci_bios_nbus. On most systems, there is
2217c478bd9Sstevel@tonic-gate 	 * one more bus at the high end, which implements the ISA
2227c478bd9Sstevel@tonic-gate 	 * compatibility bus. We don't care about that.
2237c478bd9Sstevel@tonic-gate 	 *
2247c478bd9Sstevel@tonic-gate 	 * Note: In the old (bootconf) enumeration, the peer bus
2257c478bd9Sstevel@tonic-gate 	 *	address did not use the bus number, and there were
2267c478bd9Sstevel@tonic-gate 	 *	too many peer busses created. The root_bus_addr is
2277c478bd9Sstevel@tonic-gate 	 *	used to maintain the old peer bus address assignment.
2287c478bd9Sstevel@tonic-gate 	 *	However, we stop enumerating phantom peers with no
2297c478bd9Sstevel@tonic-gate 	 *	device below.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 	for (i = 1; i <= pci_bios_nbus; i++) {
2327c478bd9Sstevel@tonic-gate 		if (pci_bus_res[i].dip == NULL) {
2337c478bd9Sstevel@tonic-gate 			pci_bus_res[i].root_addr = root_bus_addr++;
2347c478bd9Sstevel@tonic-gate 		}
2357c478bd9Sstevel@tonic-gate 		enumerate_bus_devs(i, CONFIG_INFO);
236b1f176e8Sjg 
237b1f176e8Sjg 		/* add slot-names property for named pci hot-plug slots */
238b1f176e8Sjg 		add_bus_slot_names_prop(i);
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
24325145214Smyers /*
24425145214Smyers  * >0 = present, 0 = not present, <0 = error
24525145214Smyers  */
24625145214Smyers static int
24725145214Smyers pci_bbn_present(int bus)
24825145214Smyers {
24925145214Smyers 	ACPI_HANDLE	hdl;
25025145214Smyers 	ACPI_BUFFER	rb;
25125145214Smyers 	int	rv;
25225145214Smyers 
25325145214Smyers 	/* no dip means no _BBN */
25425145214Smyers 	if (pci_bus_res[bus].dip == NULL)
25525145214Smyers 		return (0);
25625145214Smyers 
2575cff7825Smh 	rv = acpica_get_handle(pci_bus_res[bus].dip, &hdl);
25825145214Smyers 	if (rv != AE_OK)
25925145214Smyers 		return (-1);
26025145214Smyers 
26125145214Smyers 	rb.Length = ACPI_ALLOCATE_BUFFER;
26225145214Smyers 
26325145214Smyers 	rv = AcpiEvaluateObject(hdl, "_BBN", NULL, &rb);
26425145214Smyers 
26525145214Smyers 	if (rb.Length > 0)
26625145214Smyers 		AcpiOsFree(rb.Pointer);
26725145214Smyers 
26825145214Smyers 	if (rv == AE_OK)
26925145214Smyers 		return (1);
27025145214Smyers 	else if (rv == AE_NOT_FOUND)
27125145214Smyers 		return (0);
27225145214Smyers 	else
27325145214Smyers 		return (-1);
27425145214Smyers }
27525145214Smyers 
27625145214Smyers /*
27725145214Smyers  * Return non-zero if any PCI bus in the system has an associated
27825145214Smyers  * _BBN object, 0 otherwise.
27925145214Smyers  */
28025145214Smyers static int
28125145214Smyers pci_roots_have_bbn(void)
28225145214Smyers {
28325145214Smyers 	int	i;
28425145214Smyers 
28525145214Smyers 	/*
28625145214Smyers 	 * Scan the PCI busses and look for at least 1 _BBN
28725145214Smyers 	 */
28825145214Smyers 	for (i = 0; i <= pci_bios_nbus; i++) {
28925145214Smyers 		/* skip non-root (peer) PCI busses */
29025145214Smyers 		if (pci_bus_res[i].par_bus != (uchar_t)-1)
29125145214Smyers 			continue;
29225145214Smyers 
29325145214Smyers 		if (pci_bbn_present(i) > 0)
29425145214Smyers 			return (1);
29525145214Smyers 	}
29625145214Smyers 	return (0);
29725145214Smyers 
29825145214Smyers }
29925145214Smyers 
30025145214Smyers /*
30125145214Smyers  * return non-zero if the machine is one on which we renumber
30225145214Smyers  * the internal pci unit-addresses
30325145214Smyers  */
30425145214Smyers static int
30525145214Smyers pci_bus_renumber()
30625145214Smyers {
307ee8c1d4aSdm 	ACPI_TABLE_HEADER *fadt;
30825145214Smyers 
309ee8c1d4aSdm 	if (pci_bus_always_renumber)
31025145214Smyers 		return (1);
311ee8c1d4aSdm 
312ee8c1d4aSdm 	/* get the FADT */
313ee8c1d4aSdm 	if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING,
314ee8c1d4aSdm 	    (ACPI_TABLE_HEADER **)&fadt) != AE_OK)
31525145214Smyers 		return (0);
31625145214Smyers 
317ee8c1d4aSdm 	/* compare OEM Table ID to "SUNm31" */
318ee8c1d4aSdm 	if (strncmp("SUNm31", fadt->OemId, 6))
319ee8c1d4aSdm 		return (0);
320ee8c1d4aSdm 	else
321ee8c1d4aSdm 		return (1);
32225145214Smyers }
32325145214Smyers 
32425145214Smyers /*
32525145214Smyers  * Initial enumeration of the physical PCI bus hierarchy can
32625145214Smyers  * leave 'gaps' in the order of peer PCI bus unit-addresses.
32725145214Smyers  * Systems with more than one peer PCI bus *must* have an ACPI
32825145214Smyers  * _BBN object associated with each peer bus; use the presence
32925145214Smyers  * of this object to remove gaps in the numbering of the peer
33025145214Smyers  * PCI bus unit-addresses - only peer busses with an associated
33125145214Smyers  * _BBN are counted.
33225145214Smyers  */
33325145214Smyers static void
33425145214Smyers pci_renumber_root_busses(void)
33525145214Smyers {
33625145214Smyers 	int pci_regs[] = {0, 0, 0};
33725145214Smyers 	int	i, root_addr = 0;
33825145214Smyers 
339ee8c1d4aSdm 	/*
340ee8c1d4aSdm 	 * Currently, we only enable the re-numbering on specific
341ee8c1d4aSdm 	 * Sun machines; this is a work-around for the more complicated
342ee8c1d4aSdm 	 * issue of upgrade changing physical device paths
343ee8c1d4aSdm 	 */
34425145214Smyers 	if (!pci_bus_renumber())
34525145214Smyers 		return;
34625145214Smyers 
34725145214Smyers 	/*
34825145214Smyers 	 * If we find no _BBN objects at all, we either don't need
34925145214Smyers 	 * to do anything or can't do anything anyway
35025145214Smyers 	 */
35125145214Smyers 	if (!pci_roots_have_bbn())
35225145214Smyers 		return;
35325145214Smyers 
35425145214Smyers 	for (i = 0; i <= pci_bios_nbus; i++) {
35525145214Smyers 		/* skip non-root (peer) PCI busses */
35625145214Smyers 		if (pci_bus_res[i].par_bus != (uchar_t)-1)
35725145214Smyers 			continue;
35825145214Smyers 
35925145214Smyers 		if (pci_bbn_present(i) < 1) {
36025145214Smyers 			pci_bus_res[i].root_addr = (uchar_t)-1;
36125145214Smyers 			continue;
36225145214Smyers 		}
36325145214Smyers 
36425145214Smyers 		ASSERT(pci_bus_res[i].dip != NULL);
36525145214Smyers 		if (pci_bus_res[i].root_addr != root_addr) {
36625145214Smyers 			/* update reg property for node */
36725145214Smyers 			pci_bus_res[i].root_addr = root_addr;
36825145214Smyers 			pci_regs[0] = pci_bus_res[i].root_addr;
36925145214Smyers 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
37025145214Smyers 			    pci_bus_res[i].dip, "reg", (int *)pci_regs, 3);
37125145214Smyers 		}
37225145214Smyers 		root_addr++;
37325145214Smyers 	}
37425145214Smyers }
37525145214Smyers 
376aaba6dfeSmyers static void
377aaba6dfeSmyers remove_resource_range(struct memlist **list, int *ranges, int range_count)
378aaba6dfeSmyers {
379aaba6dfeSmyers 	struct range {
380aaba6dfeSmyers 		uint32_t base;
381aaba6dfeSmyers 		uint32_t len;
382aaba6dfeSmyers 	};
383aaba6dfeSmyers 	int index;
384aaba6dfeSmyers 
385aaba6dfeSmyers 	for (index = 0; index < range_count; index++) {
386328364c0Smyers 		/* all done if list is or has become empty */
387328364c0Smyers 		if (*list == NULL)
388328364c0Smyers 			break;
389aaba6dfeSmyers 		(void) memlist_remove(list,
390aaba6dfeSmyers 		    (uint64_t)((struct range *)ranges)[index].base,
391aaba6dfeSmyers 		    (uint64_t)((struct range *)ranges)[index].len);
392aaba6dfeSmyers 	}
393aaba6dfeSmyers }
394aaba6dfeSmyers 
395aaba6dfeSmyers static void
396aaba6dfeSmyers remove_used_resources()
397aaba6dfeSmyers {
398aaba6dfeSmyers 	dev_info_t *used;
399aaba6dfeSmyers 	int	*narray;
400aaba6dfeSmyers 	uint_t	ncount;
401aaba6dfeSmyers 	int	status;
402aaba6dfeSmyers 	int	bus;
403aaba6dfeSmyers 
404aaba6dfeSmyers 	used = ddi_find_devinfo("used-resources", -1, 0);
405328364c0Smyers 	if (used == NULL)
406aaba6dfeSmyers 		return;
407aaba6dfeSmyers 
408aaba6dfeSmyers 	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
409aaba6dfeSmyers 	    DDI_PROP_DONTPASS, "io-space", &narray, &ncount);
410aaba6dfeSmyers 	if (status == DDI_PROP_SUCCESS) {
411aaba6dfeSmyers 		for (bus = 0; bus <= pci_bios_nbus; bus++)
412328364c0Smyers 			remove_resource_range(&pci_bus_res[bus].io_ports,
413328364c0Smyers 			    narray, ncount / 2);
414aaba6dfeSmyers 		ddi_prop_free(narray);
415aaba6dfeSmyers 	}
416aaba6dfeSmyers 
417aaba6dfeSmyers 	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
418aaba6dfeSmyers 	    DDI_PROP_DONTPASS, "device-memory", &narray, &ncount);
419aaba6dfeSmyers 	if (status == DDI_PROP_SUCCESS) {
420aaba6dfeSmyers 		for (bus = 0; bus <= pci_bios_nbus; bus++)
421328364c0Smyers 			remove_resource_range(&pci_bus_res[bus].mem_space,
4229896aa55Sjveta 			    narray, ncount / 2);
423aaba6dfeSmyers 		ddi_prop_free(narray);
424aaba6dfeSmyers 	}
425aaba6dfeSmyers }
426aaba6dfeSmyers 
4275af4ae46Sjveta /*
428*05f867c3Sgs  * Remove the resources which are already used by devices under a subtractive
429*05f867c3Sgs  * bridge from the bus's resources lists, because they're not available, and
430*05f867c3Sgs  * shouldn't be allocated to other buses.  This is necessary because tracking
431*05f867c3Sgs  * resources for subtractive bridges is not complete.  (Subtractive bridges only
432*05f867c3Sgs  * track some of their claimed resources, not "the rest of the address space" as
433*05f867c3Sgs  * they should, so that allocation to peer non-subtractive PPBs is easier.  We
434*05f867c3Sgs  * need a fully-capable global resource allocator).
4355af4ae46Sjveta  */
436*05f867c3Sgs static void
437*05f867c3Sgs remove_subtractive_res()
4385af4ae46Sjveta {
439*05f867c3Sgs 	int i, j;
440*05f867c3Sgs 	struct memlist *list;
4415af4ae46Sjveta 
442*05f867c3Sgs 	for (i = 0; i <= pci_bios_nbus; i++) {
443*05f867c3Sgs 		if (pci_bus_res[i].subtractive) {
444*05f867c3Sgs 			/* remove used io ports */
445*05f867c3Sgs 			list = pci_bus_res[i].io_ports_used;
446*05f867c3Sgs 			while (list) {
447*05f867c3Sgs 				for (j = 0; j <= pci_bios_nbus; j++) {
448*05f867c3Sgs 					if (pci_bus_res[j].io_ports)
449*05f867c3Sgs 						(void) memlist_remove(
450*05f867c3Sgs 						    &pci_bus_res[j].io_ports,
451*05f867c3Sgs 						    list->address, list->size);
452*05f867c3Sgs 				}
453*05f867c3Sgs 				list = list->next;
454*05f867c3Sgs 			}
455*05f867c3Sgs 			/* remove used mem resource */
456*05f867c3Sgs 			list = pci_bus_res[i].mem_space_used;
457*05f867c3Sgs 			while (list) {
458*05f867c3Sgs 				for (j = 0; j <= pci_bios_nbus; j++) {
459*05f867c3Sgs 					if (pci_bus_res[j].mem_space)
460*05f867c3Sgs 						(void) memlist_remove(
461*05f867c3Sgs 						    &pci_bus_res[j].mem_space,
462*05f867c3Sgs 						    list->address, list->size);
463*05f867c3Sgs 				}
464*05f867c3Sgs 				list = list->next;
465*05f867c3Sgs 			}
466*05f867c3Sgs 			/* remove used prefetchable mem resource */
467*05f867c3Sgs 			list = pci_bus_res[i].pmem_space_used;
468*05f867c3Sgs 			while (list) {
469*05f867c3Sgs 				for (j = 0; j <= pci_bios_nbus; j++) {
470*05f867c3Sgs 					if (pci_bus_res[j].pmem_space)
471*05f867c3Sgs 						(void) memlist_remove(
472*05f867c3Sgs 						    &pci_bus_res[j].pmem_space,
473*05f867c3Sgs 						    list->address, list->size);
474*05f867c3Sgs 				}
475*05f867c3Sgs 				list = list->next;
476*05f867c3Sgs 			}
4775af4ae46Sjveta 		}
478*05f867c3Sgs 	}
479*05f867c3Sgs }
480*05f867c3Sgs 
481*05f867c3Sgs /* Set up this bus's "bus_space" resource list */
482*05f867c3Sgs static void
483*05f867c3Sgs setup_bus_res(int bus)
484*05f867c3Sgs {
485*05f867c3Sgs 	uchar_t par_bus;
486*05f867c3Sgs 	uchar_t sub_bus;
487*05f867c3Sgs 
488*05f867c3Sgs 	if (pci_bus_res[bus].dip == NULL)	/* unused bus */
489*05f867c3Sgs 		return;
490*05f867c3Sgs 
491*05f867c3Sgs 	sub_bus = pci_bus_res[bus].sub_bus;
492*05f867c3Sgs 	ASSERT(sub_bus >= bus);
493*05f867c3Sgs 	ASSERT(pci_bus_res[bus].bus_space == NULL);
494*05f867c3Sgs 	if (sub_bus > bus) {
495*05f867c3Sgs 		/*
496*05f867c3Sgs 		 * Keep the remaining available bus range in bus_space.
497*05f867c3Sgs 		 * ('bus' is already allocated)
498*05f867c3Sgs 		 */
499*05f867c3Sgs 		memlist_insert(&pci_bus_res[bus].bus_space, bus + 1,
500*05f867c3Sgs 		    sub_bus - bus);
501*05f867c3Sgs 	}
5025af4ae46Sjveta 
503*05f867c3Sgs 	/*
504*05f867c3Sgs 	 * Remove resources from parent bus node if this is not a
505*05f867c3Sgs 	 * root bus.
506*05f867c3Sgs 	 */
507*05f867c3Sgs 	par_bus = pci_bus_res[bus].par_bus;
508*05f867c3Sgs 	if (par_bus != (uchar_t)-1) {
509*05f867c3Sgs 		ASSERT(pci_bus_res[par_bus].bus_space != NULL);
510*05f867c3Sgs 		(void) memlist_remove(&pci_bus_res[par_bus].bus_space,
511*05f867c3Sgs 		    bus, sub_bus - bus + 1);
512*05f867c3Sgs 	}
5135af4ae46Sjveta }
5145af4ae46Sjveta 
515*05f867c3Sgs static uint64_t
516*05f867c3Sgs get_parbus_io_res(uchar_t parbus, uchar_t bus, uint64_t size, uint64_t align)
5175af4ae46Sjveta {
518*05f867c3Sgs 	uint64_t addr = 0;
519*05f867c3Sgs 	uchar_t res_bus;
5205af4ae46Sjveta 
521*05f867c3Sgs 	/*
522*05f867c3Sgs 	 * Skip root(peer) buses in multiple-root-bus systems, as currently
523*05f867c3Sgs 	 * the initial resources set on each root bus might not be correctly
524*05f867c3Sgs 	 * accounted for.  (We need to read resources from ACPI as well as
525*05f867c3Sgs 	 * the MP tables and hotplug tables.)
526*05f867c3Sgs 	 */
527*05f867c3Sgs 	if ((pci_bus_res[parbus].par_bus == (uchar_t)-1) &&
528*05f867c3Sgs 	    (num_root_bus > 1))
5295af4ae46Sjveta 		return (0);
5305af4ae46Sjveta 
531*05f867c3Sgs 	res_bus = parbus;
532*05f867c3Sgs 	while (pci_bus_res[res_bus].subtractive) {
533*05f867c3Sgs 		if (pci_bus_res[res_bus].io_ports)
534*05f867c3Sgs 			break;
535*05f867c3Sgs 		res_bus = pci_bus_res[res_bus].par_bus;
536*05f867c3Sgs 		if (res_bus == (uchar_t)-1)
537*05f867c3Sgs 			break; /* root bus already */
538*05f867c3Sgs 	}
5395af4ae46Sjveta 
540*05f867c3Sgs 	if (pci_bus_res[res_bus].io_ports) {
541*05f867c3Sgs 		addr = memlist_find(&pci_bus_res[res_bus].io_ports,
542*05f867c3Sgs 		    size, align);
543*05f867c3Sgs 		if (addr) {
544*05f867c3Sgs 			memlist_insert(&pci_bus_res[res_bus].io_ports_used,
545*05f867c3Sgs 			    addr, size);
546*05f867c3Sgs 			/* free the old resource */
547*05f867c3Sgs 			memlist_free_all(&pci_bus_res[bus].io_ports);
548*05f867c3Sgs 			/* add the new resource */
549*05f867c3Sgs 			memlist_insert(&pci_bus_res[bus].io_ports, addr, size);
550*05f867c3Sgs 		}
5515af4ae46Sjveta 	}
5525af4ae46Sjveta 
553*05f867c3Sgs 	return (addr);
554*05f867c3Sgs }
555*05f867c3Sgs 
556*05f867c3Sgs static uint64_t
557*05f867c3Sgs get_parbus_mem_res(uchar_t parbus, uchar_t bus, uint64_t size, uint64_t align)
558*05f867c3Sgs {
559*05f867c3Sgs 	uint64_t addr = 0;
560*05f867c3Sgs 	uchar_t res_bus;
5615af4ae46Sjveta 
5625af4ae46Sjveta 	/*
563*05f867c3Sgs 	 * Skip root(peer) buses in multiple-root-bus systems, as currently
564*05f867c3Sgs 	 * the initial resources set on each root bus might not be correctly
565*05f867c3Sgs 	 * accounted for.  (We need to read resources from ACPI as well as
566*05f867c3Sgs 	 * the MP tables and hotplug tables.)
5675af4ae46Sjveta 	 */
568*05f867c3Sgs 	if ((pci_bus_res[parbus].par_bus == (uchar_t)-1) &&
569*05f867c3Sgs 	    (num_root_bus > 1))
5705af4ae46Sjveta 		return (0);
5715af4ae46Sjveta 
572*05f867c3Sgs 	res_bus = parbus;
573*05f867c3Sgs 	while (pci_bus_res[res_bus].subtractive) {
574*05f867c3Sgs 		if (pci_bus_res[res_bus].mem_space)
575*05f867c3Sgs 			break;
576*05f867c3Sgs 		res_bus = pci_bus_res[res_bus].par_bus;
577*05f867c3Sgs 		if (res_bus == (uchar_t)-1)
578*05f867c3Sgs 			break; /* root bus already */
579*05f867c3Sgs 	}
580*05f867c3Sgs 
581*05f867c3Sgs 	if (pci_bus_res[res_bus].mem_space) {
582*05f867c3Sgs 		addr = memlist_find(&pci_bus_res[res_bus].mem_space,
583*05f867c3Sgs 		    size, align);
584*05f867c3Sgs 		if (addr) {
585*05f867c3Sgs 			memlist_insert(&pci_bus_res[res_bus].mem_space_used,
586*05f867c3Sgs 			    addr, size);
587*05f867c3Sgs 			/* free the old resource */
588*05f867c3Sgs 			memlist_free_all(&pci_bus_res[bus].mem_space);
589*05f867c3Sgs 			/* add the new resource */
590*05f867c3Sgs 			memlist_insert(&pci_bus_res[bus].mem_space, addr, size);
591*05f867c3Sgs 		}
592*05f867c3Sgs 	}
593*05f867c3Sgs 
594*05f867c3Sgs 	return (addr);
5955af4ae46Sjveta }
5965af4ae46Sjveta 
5979896aa55Sjveta /*
598*05f867c3Sgs  * Assign valid resources to unconfigured pci(e) bridges. We are trying
599*05f867c3Sgs  * to reprogram the bridge when its
600*05f867c3Sgs  * 		i)   SECBUS == SUBBUS	||
601*05f867c3Sgs  * 		ii)  IOBASE > IOLIM	||
602*05f867c3Sgs  * 		iii) MEMBASE > MEMLIM
603*05f867c3Sgs  * This must be done after one full pass through the PCI tree to collect
604*05f867c3Sgs  * all BIOS-configured resources, so that we know what resources are
605*05f867c3Sgs  * free and available to assign to the unconfigured PPBs.
6069896aa55Sjveta  */
6079896aa55Sjveta static void
608*05f867c3Sgs fix_ppb_res(uchar_t secbus, boolean_t prog_sub)
6099896aa55Sjveta {
6109896aa55Sjveta 	uchar_t bus, dev, func;
611*05f867c3Sgs 	uchar_t parbus, subbus;
612*05f867c3Sgs 	uint_t io_base, io_limit, mem_base, mem_limit;
613*05f867c3Sgs 	uint_t io_size, mem_size;
614*05f867c3Sgs 	uint64_t addr = 0;
6155af4ae46Sjveta 	int *regp = NULL;
6169896aa55Sjveta 	uint_t reglen;
6175af4ae46Sjveta 	int rv, cap_ptr, physhi;
6189896aa55Sjveta 	dev_info_t *dip;
619*05f867c3Sgs 	uint16_t cmd_reg;
620*05f867c3Sgs 	struct memlist *list;
621*05f867c3Sgs 
622*05f867c3Sgs 	/* skip root (peer) PCI busses */
623*05f867c3Sgs 	if (pci_bus_res[secbus].par_bus == (uchar_t)-1)
624*05f867c3Sgs 		return;
625*05f867c3Sgs 
626*05f867c3Sgs 	/* skip subtractive PPB when prog_sub is not TRUE */
627*05f867c3Sgs 	if (pci_bus_res[secbus].subtractive && !prog_sub)
628*05f867c3Sgs 		return;
6299896aa55Sjveta 
6309896aa55Sjveta 	/* some entries may be empty due to discontiguous bus numbering */
6315af4ae46Sjveta 	dip = pci_bus_res[secbus].dip;
6329896aa55Sjveta 	if (dip == NULL)
6339896aa55Sjveta 		return;
6349896aa55Sjveta 
6359896aa55Sjveta 	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
6369896aa55Sjveta 	    "reg", &regp, &reglen);
6375af4ae46Sjveta 	ASSERT(rv == DDI_PROP_SUCCESS && reglen > 0);
6385af4ae46Sjveta 	physhi = regp[0];
6395af4ae46Sjveta 	ddi_prop_free(regp);
6409896aa55Sjveta 
6415af4ae46Sjveta 	func = (uchar_t)PCI_REG_FUNC_G(physhi);
6425af4ae46Sjveta 	dev = (uchar_t)PCI_REG_DEV_G(physhi);
6435af4ae46Sjveta 	bus = (uchar_t)PCI_REG_BUS_G(physhi);
6449896aa55Sjveta 
6459896aa55Sjveta 	/*
646*05f867c3Sgs 	 * If pcie bridge, check to see if link is enabled
6479896aa55Sjveta 	 */
6485af4ae46Sjveta 	cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
6495af4ae46Sjveta 	    "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
650*05f867c3Sgs 	if (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
651*05f867c3Sgs 		cmd_reg = pci_getw(bus, dev, func,
652*05f867c3Sgs 		    (uint16_t)cap_ptr + PCIE_LINKCTL);
653*05f867c3Sgs 		if (cmd_reg & PCIE_LINKCTL_LINK_DISABLE) {
654*05f867c3Sgs 			dcmn_err(CE_NOTE,
655*05f867c3Sgs 			    "!fix_ppb_res: ppb[%x/%x/%x] link is disabled.\n",
656*05f867c3Sgs 			    bus, dev, func);
657*05f867c3Sgs 			return;
658*05f867c3Sgs 		}
659*05f867c3Sgs 	}
6609896aa55Sjveta 
661*05f867c3Sgs 	subbus = pci_getb(bus, dev, func, PCI_BCNF_SUBBUS);
662*05f867c3Sgs 	parbus = pci_bus_res[secbus].par_bus;
663*05f867c3Sgs 	ASSERT(parbus == bus);
6649896aa55Sjveta 
6655af4ae46Sjveta 	/*
666*05f867c3Sgs 	 * If we have a Cardbus bridge, but no bus space
6675af4ae46Sjveta 	 */
668*05f867c3Sgs 	if (pci_bus_res[secbus].num_cbb != 0 &&
669*05f867c3Sgs 	    pci_bus_res[secbus].bus_space == NULL) {
670*05f867c3Sgs 		uchar_t range;
6715af4ae46Sjveta 
672*05f867c3Sgs 		/* normally there are 2 buses under a cardbus bridge */
673*05f867c3Sgs 		range = pci_bus_res[secbus].num_cbb * 2;
674*05f867c3Sgs 
675*05f867c3Sgs 		/*
676*05f867c3Sgs 		 * Try to find and allocate a bus-range starting at subbus+1
677*05f867c3Sgs 		 * from the parent of the PPB.
678*05f867c3Sgs 		 */
679*05f867c3Sgs 		for (; range != 0; range--) {
680*05f867c3Sgs 			if (memlist_find_with_startaddr(
681*05f867c3Sgs 			    &pci_bus_res[parbus].bus_space,
682*05f867c3Sgs 			    subbus + 1, range, 1) != NULL)
683*05f867c3Sgs 				break; /* find bus range resource at parent */
684*05f867c3Sgs 		}
685*05f867c3Sgs 		if (range != 0) {
686*05f867c3Sgs 			memlist_insert(&pci_bus_res[secbus].bus_space,
687*05f867c3Sgs 			    subbus + 1, range);
688*05f867c3Sgs 			subbus = subbus + range;
689*05f867c3Sgs 			pci_bus_res[secbus].sub_bus = subbus;
690*05f867c3Sgs 			pci_putb(bus, dev, func, PCI_BCNF_SUBBUS, subbus);
691*05f867c3Sgs 			add_bus_range_prop(secbus);
692*05f867c3Sgs 
693*05f867c3Sgs 			cmn_err(CE_NOTE, "!reprogram bus-range on ppb"
694*05f867c3Sgs 			    "[%x/%x/%x]: %x ~ %x\n", bus, dev, func,
695*05f867c3Sgs 			    secbus, subbus);
696*05f867c3Sgs 		}
697*05f867c3Sgs 	}
698*05f867c3Sgs 
699*05f867c3Sgs 	/*
700*05f867c3Sgs 	 * Calculate required IO size
701*05f867c3Sgs 	 * We are going to assign 512 bytes per bus. The size needs to be
702*05f867c3Sgs 	 * 4K aligned and the maximum size is 16K.
703*05f867c3Sgs 	 */
704*05f867c3Sgs 	io_size = (subbus - secbus + 1) * 0x200;
705*05f867c3Sgs 	io_size = (io_size + PPB_IO_ALIGNMENT) & (~(PPB_IO_ALIGNMENT - 1));
706*05f867c3Sgs 	if (io_size > 0x4 * PPB_IO_ALIGNMENT)
707*05f867c3Sgs 		io_size = 0x4 * PPB_IO_ALIGNMENT;
7085af4ae46Sjveta 	/*
709*05f867c3Sgs 	 * Calculate required MEM size
710*05f867c3Sgs 	 * We are going to assign 1M bytes per bus. The size needs to be
711*05f867c3Sgs 	 * 1M aligned and the maximum size is 8M.
7125af4ae46Sjveta 	 */
713*05f867c3Sgs 	mem_size = (subbus - secbus + 1) * PPB_MEM_ALIGNMENT;
714*05f867c3Sgs 	if (mem_size > 0x8 * PPB_MEM_ALIGNMENT)
715*05f867c3Sgs 		mem_size = 0x8 * PPB_MEM_ALIGNMENT;
716*05f867c3Sgs 
717*05f867c3Sgs 	/* Subtractive bridge */
718*05f867c3Sgs 	if (pci_bus_res[secbus].subtractive && prog_sub) {
719*05f867c3Sgs 		/*
720*05f867c3Sgs 		 * We program an arbitrary amount of I/O and memory resource
721*05f867c3Sgs 		 * for the subtractive bridge so that child dynamic-resource-
722*05f867c3Sgs 		 * allocating devices (such as Cardbus bridges) have a chance
723*05f867c3Sgs 		 * of success.  Until we have full-tree resource rebalancing,
724*05f867c3Sgs 		 * dynamic resource allocation (thru busra) only looks at the
725*05f867c3Sgs 		 * parent bridge, so all PPBs must have some allocatable
726*05f867c3Sgs 		 * resource.  For non-subtractive bridges, the resources come
727*05f867c3Sgs 		 * from the base/limit register "windows", but subtractive
728*05f867c3Sgs 		 * bridges often don't program those (since they don't need to).
729*05f867c3Sgs 		 * If we put all the remaining resources on the subtractive
730*05f867c3Sgs 		 * bridge, then peer non-subtractive bridges can't allocate
731*05f867c3Sgs 		 * more space (even though this is probably most correct).
732*05f867c3Sgs 		 * If we put the resources only on the parent, then allocations
733*05f867c3Sgs 		 * from children of subtractive bridges will fail without
734*05f867c3Sgs 		 * special-case code for bypassing the subtractive bridge.
735*05f867c3Sgs 		 * This solution is the middle-ground temporary solution until
736*05f867c3Sgs 		 * we have fully-capable resource allocation.
737*05f867c3Sgs 		 */
738*05f867c3Sgs 
739*05f867c3Sgs 		/*
740*05f867c3Sgs 		 * Add an arbitrary I/O resource to the subtractive PPB
741*05f867c3Sgs 		 */
742*05f867c3Sgs 		if (pci_bus_res[secbus].io_ports == NULL) {
743*05f867c3Sgs 			addr = get_parbus_io_res(parbus, secbus, io_size,
744*05f867c3Sgs 			    PPB_IO_ALIGNMENT);
745*05f867c3Sgs 			if (addr) {
746*05f867c3Sgs 				add_ppb_ranges_prop(secbus);
747*05f867c3Sgs 				pci_bus_res[secbus].io_reprogram =
748*05f867c3Sgs 				    pci_bus_res[parbus].io_reprogram;
749*05f867c3Sgs 
750*05f867c3Sgs 				cmn_err(CE_NOTE, "!add io-range on subtractive"
751*05f867c3Sgs 				    " ppb[%x/%x/%x]: 0x%x ~ 0x%x\n",
752*05f867c3Sgs 				    bus, dev, func, (uint32_t)addr,
753*05f867c3Sgs 				    (uint32_t)addr + io_size - 1);
754*05f867c3Sgs 			}
755*05f867c3Sgs 		}
756*05f867c3Sgs 		/*
757*05f867c3Sgs 		 * Add an arbitrary memory resource to the subtractive PPB
758*05f867c3Sgs 		 */
759*05f867c3Sgs 		if (pci_bus_res[secbus].mem_space == NULL) {
760*05f867c3Sgs 			addr = get_parbus_mem_res(parbus, secbus, mem_size,
761*05f867c3Sgs 			    PPB_MEM_ALIGNMENT);
762*05f867c3Sgs 			if (addr) {
763*05f867c3Sgs 				add_ppb_ranges_prop(secbus);
764*05f867c3Sgs 				pci_bus_res[secbus].mem_reprogram =
765*05f867c3Sgs 				    pci_bus_res[parbus].mem_reprogram;
766*05f867c3Sgs 
767*05f867c3Sgs 				cmn_err(CE_NOTE, "!add mem-range on "
768*05f867c3Sgs 				    "subtractive ppb[%x/%x/%x]: 0x%x ~ 0x%x\n",
769*05f867c3Sgs 				    bus, dev, func, (uint32_t)addr,
770*05f867c3Sgs 				    (uint32_t)addr + mem_size - 1);
771*05f867c3Sgs 			}
772*05f867c3Sgs 		}
773*05f867c3Sgs 
774*05f867c3Sgs 		goto cmd_enable;
7755af4ae46Sjveta 	}
776*05f867c3Sgs 
777*05f867c3Sgs 	/*
778*05f867c3Sgs 	 * io_base > io_limit means that the bridge was not configured
779*05f867c3Sgs 	 * This may have been set by the BIOS or by add_ppb_props()
780*05f867c3Sgs 	 * if I/O space is disabled in the Command register.
781*05f867c3Sgs 	 */
782*05f867c3Sgs 	io_base = pci_getb(bus, dev, func, PCI_BCNF_IO_BASE_LOW);
783*05f867c3Sgs 	io_limit = pci_getb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW);
784*05f867c3Sgs 	io_base = (io_base & 0xf0) << 8;
785*05f867c3Sgs 	io_limit = ((io_limit & 0xf0) << 8) | 0xfff;
786*05f867c3Sgs 
787*05f867c3Sgs 	if (pci_bus_res[parbus].io_reprogram || (io_base > io_limit)) {
788*05f867c3Sgs 		if (pci_bus_res[secbus].io_ports_used) {
789*05f867c3Sgs 			memlist_merge(&pci_bus_res[secbus].io_ports_used,
790*05f867c3Sgs 			    &pci_bus_res[secbus].io_ports);
791*05f867c3Sgs 		}
792*05f867c3Sgs 		if (pci_bus_res[secbus].io_ports &&
793*05f867c3Sgs 		    (!pci_bus_res[parbus].io_reprogram) &&
794*05f867c3Sgs 		    (!pci_bus_res[parbus].subtractive)) {
795*05f867c3Sgs 			/* rechoose old io ports info */
796*05f867c3Sgs 			list = pci_bus_res[secbus].io_ports;
797*05f867c3Sgs 			io_base = (uint_t)list->address;
798*05f867c3Sgs 			/* 4K aligned */
799*05f867c3Sgs 			io_base = io_base & (~(PPB_IO_ALIGNMENT - 1));
800*05f867c3Sgs 			io_limit = (uint_t)(list->address + list->size);
801*05f867c3Sgs 			while (list->next) {
802*05f867c3Sgs 				list = list->next;
803*05f867c3Sgs 				if ((list->address + list->size) > io_limit)
804*05f867c3Sgs 					io_limit = (uint_t)
805*05f867c3Sgs 					    (list->address + list->size);
806*05f867c3Sgs 			}
807*05f867c3Sgs 			io_limit = io_limit - 1;
808*05f867c3Sgs 			/* 4K aligned */
809*05f867c3Sgs 			io_limit = (io_limit + PPB_IO_ALIGNMENT) &
810*05f867c3Sgs 			    (~(PPB_IO_ALIGNMENT - 1));
811*05f867c3Sgs 			io_size = io_limit - io_base;
812*05f867c3Sgs 			io_limit = io_limit - 1;
813*05f867c3Sgs 			ASSERT(io_base <= io_limit);
814*05f867c3Sgs 			memlist_free_all(&pci_bus_res[secbus].io_ports);
815*05f867c3Sgs 			memlist_insert(&pci_bus_res[secbus].io_ports,
816*05f867c3Sgs 			    io_base, io_size);
817*05f867c3Sgs 			memlist_insert(&pci_bus_res[parbus].io_ports_used,
818*05f867c3Sgs 			    io_base, io_size);
819*05f867c3Sgs 			if (pci_bus_res[parbus].io_ports)
820*05f867c3Sgs 				(void) memlist_remove(
821*05f867c3Sgs 				    &pci_bus_res[parbus].io_ports,
822*05f867c3Sgs 				    io_base, io_size);
823*05f867c3Sgs 			pci_bus_res[secbus].io_reprogram = B_TRUE;
824*05f867c3Sgs 		} else {
825*05f867c3Sgs 			/* get new io ports from parent bus */
826*05f867c3Sgs 			addr = get_parbus_io_res(parbus, secbus, io_size,
827*05f867c3Sgs 			    PPB_IO_ALIGNMENT);
828*05f867c3Sgs 			if (addr) {
829*05f867c3Sgs 				io_base = addr;
830*05f867c3Sgs 				io_limit = addr + io_size - 1;
831*05f867c3Sgs 				pci_bus_res[secbus].io_reprogram = B_TRUE;
832*05f867c3Sgs 			}
833*05f867c3Sgs 		}
834*05f867c3Sgs 		if (pci_bus_res[secbus].io_reprogram) {
835*05f867c3Sgs 			/* reprogram PPB regs */
836*05f867c3Sgs 			pci_putb(bus, dev, func, PCI_BCNF_IO_BASE_LOW,
837*05f867c3Sgs 			    (uchar_t)((io_base>>8) & 0xf0));
838*05f867c3Sgs 			pci_putb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW,
839*05f867c3Sgs 			    (uchar_t)((io_limit>>8) & 0xf0));
840*05f867c3Sgs 			pci_putb(bus, dev, func, PCI_BCNF_IO_BASE_HI, 0);
841*05f867c3Sgs 			pci_putb(bus, dev, func, PCI_BCNF_IO_LIMIT_HI, 0);
842*05f867c3Sgs 			add_ppb_ranges_prop(secbus);
843*05f867c3Sgs 
844*05f867c3Sgs 			cmn_err(CE_NOTE, "!reprogram io-range on"
845*05f867c3Sgs 			    " ppb[%x/%x/%x]: 0x%x ~ 0x%x\n",
846*05f867c3Sgs 			    bus, dev, func, io_base, io_limit);
847*05f867c3Sgs 		}
8489896aa55Sjveta 	}
8499896aa55Sjveta 
8505af4ae46Sjveta 	/*
851*05f867c3Sgs 	 * mem_base > mem_limit
8525af4ae46Sjveta 	 */
853*05f867c3Sgs 	mem_base = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_BASE);
854*05f867c3Sgs 	mem_base = (mem_base & 0xfff0) << 16;
855*05f867c3Sgs 	mem_limit = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_LIMIT);
856*05f867c3Sgs 	mem_limit = ((mem_limit & 0xfff0) << 16) |0xfffff;
857*05f867c3Sgs 	if (pci_bus_res[parbus].mem_reprogram || (mem_base > mem_limit)) {
858*05f867c3Sgs 		if (pci_bus_res[secbus].mem_space_used) {
859*05f867c3Sgs 			memlist_merge(&pci_bus_res[secbus].mem_space_used,
860*05f867c3Sgs 			    &pci_bus_res[secbus].mem_space);
861*05f867c3Sgs 		}
862*05f867c3Sgs 		if (pci_bus_res[secbus].mem_space &&
863*05f867c3Sgs 		    (!pci_bus_res[parbus].mem_reprogram) &&
864*05f867c3Sgs 		    (!pci_bus_res[parbus].subtractive)) {
865*05f867c3Sgs 			/* rechoose old mem resource */
866*05f867c3Sgs 			list = pci_bus_res[secbus].mem_space;
867*05f867c3Sgs 			mem_base = (uint_t)list->address;
868*05f867c3Sgs 			/* 1M aligned */
869*05f867c3Sgs 			mem_base = mem_base & (~0xfffff);
870*05f867c3Sgs 			mem_limit = (uint_t)(list->address + list->size);
871*05f867c3Sgs 			while (list->next) {
872*05f867c3Sgs 				list = list->next;
873*05f867c3Sgs 				if ((list->address + list->size) > mem_limit)
874*05f867c3Sgs 					mem_limit = (uint_t)
875*05f867c3Sgs 					    (list->address + list->size);
876*05f867c3Sgs 			}
877*05f867c3Sgs 			mem_limit = mem_limit - 1;
878*05f867c3Sgs 			/* 1M aligned */
879*05f867c3Sgs 			mem_limit = (mem_limit + PPB_MEM_ALIGNMENT) &
880*05f867c3Sgs 			    (~(PPB_MEM_ALIGNMENT - 1));
881*05f867c3Sgs 			mem_size = mem_limit - mem_base;
882*05f867c3Sgs 			mem_limit = mem_limit - 1;
883*05f867c3Sgs 			ASSERT(mem_base <= mem_limit);
884*05f867c3Sgs 			memlist_free_all(&pci_bus_res[secbus].mem_space);
885*05f867c3Sgs 			memlist_insert(&pci_bus_res[secbus].mem_space,
886*05f867c3Sgs 			    mem_base, mem_size);
887*05f867c3Sgs 			memlist_insert(&pci_bus_res[parbus].mem_space_used,
888*05f867c3Sgs 			    mem_base, mem_size);
889*05f867c3Sgs 			if (pci_bus_res[parbus].mem_space)
890*05f867c3Sgs 				(void) memlist_remove(
891*05f867c3Sgs 				    &pci_bus_res[parbus].mem_space,
892*05f867c3Sgs 				    mem_base, mem_size);
893*05f867c3Sgs 			pci_bus_res[secbus].mem_reprogram = B_TRUE;
894*05f867c3Sgs 		} else {
895*05f867c3Sgs 			/* get new mem resource from parent bus */
896*05f867c3Sgs 			addr = get_parbus_mem_res(parbus, secbus, mem_size,
897*05f867c3Sgs 			    PPB_MEM_ALIGNMENT);
898*05f867c3Sgs 			if (addr) {
899*05f867c3Sgs 				mem_base = addr;
900*05f867c3Sgs 				mem_limit = addr + mem_size - 1;
901*05f867c3Sgs 				pci_bus_res[secbus].mem_reprogram = B_TRUE;
902*05f867c3Sgs 			}
903*05f867c3Sgs 		}
904*05f867c3Sgs 
905*05f867c3Sgs 		if (pci_bus_res[secbus].mem_reprogram) {
906*05f867c3Sgs 			/* reprogram PPB regs */
907*05f867c3Sgs 			pci_putw(bus, dev, func, PCI_BCNF_MEM_BASE,
908*05f867c3Sgs 			    (uint16_t)((mem_base>>16) & 0xfff0));
909*05f867c3Sgs 			pci_putw(bus, dev, func, PCI_BCNF_MEM_LIMIT,
910*05f867c3Sgs 			    (uint16_t)((mem_limit>>16) & 0xfff0));
911*05f867c3Sgs 			add_ppb_ranges_prop(secbus);
912*05f867c3Sgs 
913*05f867c3Sgs 			cmn_err(CE_NOTE, "!reprogram mem-range on"
914*05f867c3Sgs 			    " ppb[%x/%x/%x]: 0x%x ~ 0x%x\n",
915*05f867c3Sgs 			    bus, dev, func, mem_base, mem_limit);
916*05f867c3Sgs 		}
917*05f867c3Sgs 	}
918*05f867c3Sgs 
919*05f867c3Sgs cmd_enable:
920*05f867c3Sgs 	cmd_reg = pci_getw(bus, dev, func, PCI_CONF_COMM);
921*05f867c3Sgs 	if (pci_bus_res[secbus].io_ports)
922*05f867c3Sgs 		cmd_reg |= PCI_COMM_IO | PCI_COMM_ME;
923*05f867c3Sgs 	if (pci_bus_res[secbus].mem_space)
924*05f867c3Sgs 		cmd_reg |= PCI_COMM_MAE | PCI_COMM_ME;
925*05f867c3Sgs 	pci_putw(bus, dev, func, PCI_CONF_COMM, cmd_reg);
9269896aa55Sjveta }
9279896aa55Sjveta 
9287c478bd9Sstevel@tonic-gate void
9297c478bd9Sstevel@tonic-gate pci_reprogram(void)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate 	int i, pci_reconfig = 1;
9327c478bd9Sstevel@tonic-gate 	char *onoff;
9337c478bd9Sstevel@tonic-gate 
93425145214Smyers 	/*
93525145214Smyers 	 * Excise phantom roots if possible
93625145214Smyers 	 */
93725145214Smyers 	pci_renumber_root_busses();
93825145214Smyers 
939fc396574Srw 	/* add bus-range property for root/peer bus nodes */
940fc396574Srw 	for (i = 0; i <= pci_bios_nbus; i++) {
941fc396574Srw 		if (pci_bus_res[i].par_bus == (uchar_t)-1) {
942fc396574Srw 			uchar_t subbus;
943fc396574Srw 			if (pci_root_subbus(i, &subbus) == AE_OK)
9449896aa55Sjveta 				pci_bus_res[i].sub_bus = subbus;
945fc396574Srw 			add_bus_range_prop(i);
946fc396574Srw 		}
947*05f867c3Sgs 		/* setup bus range resource on each bus */
948*05f867c3Sgs 		setup_bus_res(i);
949fc396574Srw 	}
950fc396574Srw 
9517c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
9527c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "pci-reprog", &onoff) == DDI_SUCCESS) {
9537c478bd9Sstevel@tonic-gate 		if (strcmp(onoff, "off") == 0) {
9547c478bd9Sstevel@tonic-gate 			pci_reconfig = 0;
9557c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "pci device reprogramming disabled");
9567c478bd9Sstevel@tonic-gate 		}
9577c478bd9Sstevel@tonic-gate 		ddi_prop_free(onoff);
9587c478bd9Sstevel@tonic-gate 	}
9597c478bd9Sstevel@tonic-gate 
960aaba6dfeSmyers 	/* remove used-resources from PCI resource maps */
961aaba6dfeSmyers 	remove_used_resources();
962*05f867c3Sgs 	remove_subtractive_res();
963*05f867c3Sgs 
964*05f867c3Sgs 	/* reprogram the non-subtractive PPB */
965*05f867c3Sgs 	if (pci_reconfig)
966*05f867c3Sgs 		for (i = 0; i <= pci_bios_nbus; i++)
967*05f867c3Sgs 			fix_ppb_res(i, B_FALSE);
968aaba6dfeSmyers 
9697c478bd9Sstevel@tonic-gate 	for (i = 0; i <= pci_bios_nbus; i++) {
970*05f867c3Sgs 		/* configure devices not configured by BIOS */
9719896aa55Sjveta 		if (pci_reconfig) {
972*05f867c3Sgs 			/*
973*05f867c3Sgs 			 * Reprogram the subtractive PPB. At this time, all its
974*05f867c3Sgs 			 * siblings should have got their resources already.
975*05f867c3Sgs 			 */
976*05f867c3Sgs 			if (pci_bus_res[i].subtractive)
977*05f867c3Sgs 				fix_ppb_res(i, B_TRUE);
9787c478bd9Sstevel@tonic-gate 			enumerate_bus_devs(i, CONFIG_NEW);
9799896aa55Sjveta 		}
9807c478bd9Sstevel@tonic-gate 		/* All dev programmed, so we can create available prop */
9817c478bd9Sstevel@tonic-gate 		add_bus_available_prop(i);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  * Create top-level bus dips, i.e. /pci@0,0, /pci@1,0...
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate static void
9897c478bd9Sstevel@tonic-gate create_root_bus_dip(uchar_t bus)
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	int pci_regs[] = {0, 0, 0};
9927c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	ASSERT(pci_bus_res[bus].par_bus == (uchar_t)-1);
9957c478bd9Sstevel@tonic-gate 
996*05f867c3Sgs 	num_root_bus++;
9977c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(ddi_root_node(), "pci",
998fa9e4066Sahrens 	    (pnode_t)DEVI_SID_NODEID, &dip);
9997c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
10007c478bd9Sstevel@tonic-gate 	    "#address-cells", 3);
10017c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
10027c478bd9Sstevel@tonic-gate 	    "#size-cells", 2);
10037c478bd9Sstevel@tonic-gate 	pci_regs[0] = pci_bus_res[bus].root_addr;
10047c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
10057c478bd9Sstevel@tonic-gate 	    "reg", (int *)pci_regs, 3);
10067c478bd9Sstevel@tonic-gate 
100770025d76Sjohnny 	/*
100870025d76Sjohnny 	 * If system has PCIe bus, then create different properties
100970025d76Sjohnny 	 */
101070025d76Sjohnny 	if (create_pcie_root_bus(bus, dip) == B_FALSE)
101170025d76Sjohnny 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
101270025d76Sjohnny 		    "device_type", "pci");
101370025d76Sjohnny 
10147c478bd9Sstevel@tonic-gate 	(void) ndi_devi_bind_driver(dip, 0);
10157c478bd9Sstevel@tonic-gate 	pci_bus_res[bus].dip = dip;
10167c478bd9Sstevel@tonic-gate 	pci_bus_res[bus].pmem_space = find_bus_res(bus, PREFETCH_TYPE);
10177c478bd9Sstevel@tonic-gate 	pci_bus_res[bus].mem_space = find_bus_res(bus, MEM_TYPE);
10187c478bd9Sstevel@tonic-gate 	pci_bus_res[bus].io_ports = find_bus_res(bus, IO_TYPE);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	if (bus != 0)
10217c478bd9Sstevel@tonic-gate 		return;
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	/*
10247c478bd9Sstevel@tonic-gate 	 * Special treatment of bus 0:
10257c478bd9Sstevel@tonic-gate 	 * If no resource from MPSPEC/HRT, copy pcimem from boot
1026aaba6dfeSmyers 	 * and make I/O space the entire range starting at 0x100. There
1027aaba6dfeSmyers 	 * is no difference between prefetchable memory or not.
10287c478bd9Sstevel@tonic-gate 	 */
10297c478bd9Sstevel@tonic-gate 	if (pci_bus_res[0].mem_space == NULL)
10307c478bd9Sstevel@tonic-gate 		pci_bus_res[0].mem_space =
10317c478bd9Sstevel@tonic-gate 		    memlist_dup(bootops->boot_mem->pcimem);
1032aaba6dfeSmyers 	/* Exclude 0x00 to 0xff of the I/O space, used by all PCs */
10337c478bd9Sstevel@tonic-gate 	if (pci_bus_res[0].io_ports == NULL)
10345af4ae46Sjveta 		memlist_insert(&pci_bus_res[0].io_ports, 0x100, 0xffff);
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate /*
10387c478bd9Sstevel@tonic-gate  * For any fixed configuration (often compatability) pci devices
10397c478bd9Sstevel@tonic-gate  * and those with their own expansion rom, create device nodes
10407c478bd9Sstevel@tonic-gate  * to hold the already configured device details.
10417c478bd9Sstevel@tonic-gate  */
10427c478bd9Sstevel@tonic-gate void
10437c478bd9Sstevel@tonic-gate enumerate_bus_devs(uchar_t bus, int config_op)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	uchar_t dev, func, nfunc, header;
10467c478bd9Sstevel@tonic-gate 	ushort_t venid;
1047*05f867c3Sgs 	struct pci_devfunc *devlist = NULL, *entry;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	if (config_op == CONFIG_NEW) {
10507c478bd9Sstevel@tonic-gate 		dcmn_err(CE_NOTE, "configuring pci bus 0x%x", bus);
1051bd87be88Ssethg 	} else if (config_op == CONFIG_FIX) {
1052bd87be88Ssethg 		dcmn_err(CE_NOTE, "fixing devices on pci bus 0x%x", bus);
10537c478bd9Sstevel@tonic-gate 	} else
10547c478bd9Sstevel@tonic-gate 		dcmn_err(CE_NOTE, "enumerating pci bus 0x%x", bus);
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	for (dev = 0; dev < max_dev_pci; dev++) {
10577c478bd9Sstevel@tonic-gate 		nfunc = 1;
10587c478bd9Sstevel@tonic-gate 		for (func = 0; func < nfunc; func++) {
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 			dcmn_err(CE_NOTE, "probing dev 0x%x, func 0x%x",
10617c478bd9Sstevel@tonic-gate 			    dev, func);
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 			venid = pci_getw(bus, dev, func, PCI_CONF_VENID);
1064bd87be88Ssethg 
10657c478bd9Sstevel@tonic-gate 			if ((venid == 0xffff) || (venid == 0)) {
10667c478bd9Sstevel@tonic-gate 				/* no function at this address */
10677c478bd9Sstevel@tonic-gate 				continue;
10687c478bd9Sstevel@tonic-gate 			}
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 			header = pci_getb(bus, dev, func, PCI_CONF_HEADER);
10717c478bd9Sstevel@tonic-gate 			if (header == 0xff) {
10727c478bd9Sstevel@tonic-gate 				continue; /* illegal value */
10737c478bd9Sstevel@tonic-gate 			}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 			/*
10767c478bd9Sstevel@tonic-gate 			 * according to some mail from Microsoft posted
10777c478bd9Sstevel@tonic-gate 			 * to the pci-drivers alias, their only requirement
10787c478bd9Sstevel@tonic-gate 			 * for a multifunction device is for the 1st
10797c478bd9Sstevel@tonic-gate 			 * function to have to PCI_HEADER_MULTI bit set.
10807c478bd9Sstevel@tonic-gate 			 */
10817c478bd9Sstevel@tonic-gate 			if ((func == 0) && (header & PCI_HEADER_MULTI)) {
10827c478bd9Sstevel@tonic-gate 				nfunc = 8;
10837c478bd9Sstevel@tonic-gate 			}
108446e9e839Smyers 
1085*05f867c3Sgs 			if (config_op == CONFIG_FIX ||
1086*05f867c3Sgs 			    config_op == CONFIG_INFO) {
1087ebf3afa8Sdmick 				/*
1088ebf3afa8Sdmick 				 * Create the node, unconditionally, on the
1089ebf3afa8Sdmick 				 * first pass only.  It may still need
1090ebf3afa8Sdmick 				 * resource assignment, which will be
1091ebf3afa8Sdmick 				 * done on the second, CONFIG_NEW, pass.
1092ebf3afa8Sdmick 				 */
1093*05f867c3Sgs 				process_devfunc(bus, dev, func, header,
1094ebf3afa8Sdmick 				    venid, config_op);
1095db063408Sdmick 
10967c478bd9Sstevel@tonic-gate 			}
10977c478bd9Sstevel@tonic-gate 		}
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	if (config_op == CONFIG_NEW) {
11017c478bd9Sstevel@tonic-gate 		devlist = (struct pci_devfunc *)pci_bus_res[bus].privdata;
11027c478bd9Sstevel@tonic-gate 		while (devlist) {
11037c478bd9Sstevel@tonic-gate 			entry = devlist;
11047c478bd9Sstevel@tonic-gate 			devlist = entry->next;
1105*05f867c3Sgs 			if (entry->reprogram ||
1106*05f867c3Sgs 			    pci_bus_res[bus].io_reprogram ||
1107*05f867c3Sgs 			    pci_bus_res[bus].mem_reprogram) {
1108*05f867c3Sgs 				/* reprogram device(s) */
1109*05f867c3Sgs 				(void) add_reg_props(entry->dip, bus,
1110*05f867c3Sgs 				    entry->dev, entry->func, CONFIG_NEW, 0);
1111*05f867c3Sgs 			}
11127c478bd9Sstevel@tonic-gate 			kmem_free(entry, sizeof (*entry));
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 		pci_bus_res[bus].privdata = NULL;
11157c478bd9Sstevel@tonic-gate 	}
11167c478bd9Sstevel@tonic-gate }
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate static int
11197c478bd9Sstevel@tonic-gate check_pciide_prop(uchar_t revid, ushort_t venid, ushort_t devid,
11207c478bd9Sstevel@tonic-gate     ushort_t subvenid, ushort_t subdevid)
11217c478bd9Sstevel@tonic-gate {
11227c478bd9Sstevel@tonic-gate 	static int prop_exist = -1;
11237c478bd9Sstevel@tonic-gate 	static char *pciide_str;
11247c478bd9Sstevel@tonic-gate 	char compat[32];
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	if (prop_exist == -1) {
11277c478bd9Sstevel@tonic-gate 		prop_exist = (ddi_prop_lookup_string(DDI_DEV_T_ANY,
11287c478bd9Sstevel@tonic-gate 		    ddi_root_node(), DDI_PROP_DONTPASS, "pci-ide",
11297c478bd9Sstevel@tonic-gate 		    &pciide_str) == DDI_SUCCESS);
11307c478bd9Sstevel@tonic-gate 	}
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	if (!prop_exist)
11337c478bd9Sstevel@tonic-gate 		return (0);
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	/* compare property value against various forms of compatible */
11367c478bd9Sstevel@tonic-gate 	if (subvenid) {
11377c478bd9Sstevel@tonic-gate 		(void) snprintf(compat, sizeof (compat), "pci%x,%x.%x.%x.%x",
11387c478bd9Sstevel@tonic-gate 		    venid, devid, subvenid, subdevid, revid);
11397c478bd9Sstevel@tonic-gate 		if (strcmp(pciide_str, compat) == 0)
11407c478bd9Sstevel@tonic-gate 			return (1);
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 		(void) snprintf(compat, sizeof (compat), "pci%x,%x.%x.%x",
11437c478bd9Sstevel@tonic-gate 		    venid, devid, subvenid, subdevid);
11447c478bd9Sstevel@tonic-gate 		if (strcmp(pciide_str, compat) == 0)
11457c478bd9Sstevel@tonic-gate 			return (1);
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 		(void) snprintf(compat, sizeof (compat), "pci%x,%x",
11487c478bd9Sstevel@tonic-gate 		    subvenid, subdevid);
11497c478bd9Sstevel@tonic-gate 		if (strcmp(pciide_str, compat) == 0)
11507c478bd9Sstevel@tonic-gate 			return (1);
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 	(void) snprintf(compat, sizeof (compat), "pci%x,%x.%x",
11537c478bd9Sstevel@tonic-gate 	    venid, devid, revid);
11547c478bd9Sstevel@tonic-gate 	if (strcmp(pciide_str, compat) == 0)
11557c478bd9Sstevel@tonic-gate 		return (1);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	(void) snprintf(compat, sizeof (compat), "pci%x,%x", venid, devid);
11587c478bd9Sstevel@tonic-gate 	if (strcmp(pciide_str, compat) == 0)
11597c478bd9Sstevel@tonic-gate 		return (1);
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	return (0);
11627c478bd9Sstevel@tonic-gate }
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate static int
11657c478bd9Sstevel@tonic-gate is_pciide(uchar_t basecl, uchar_t subcl, uchar_t revid,
11667c478bd9Sstevel@tonic-gate     ushort_t venid, ushort_t devid, ushort_t subvenid, ushort_t subdevid)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	struct ide_table {	/* table for PCI_MASS_OTHER */
11697c478bd9Sstevel@tonic-gate 		ushort_t venid;
11707c478bd9Sstevel@tonic-gate 		ushort_t devid;
11717c478bd9Sstevel@tonic-gate 	} *entry;
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	/* XXX SATA devices: need a way to add dynamically */
11747c478bd9Sstevel@tonic-gate 	static struct ide_table ide_other[] = {
11757c478bd9Sstevel@tonic-gate 		{0x1095, 0x3112},
11767c478bd9Sstevel@tonic-gate 		{0x1095, 0x3114},
11777c478bd9Sstevel@tonic-gate 		{0x1095, 0x3512},
11787c478bd9Sstevel@tonic-gate 		{0, 0}
11797c478bd9Sstevel@tonic-gate 	};
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	if (basecl != PCI_CLASS_MASS)
11827c478bd9Sstevel@tonic-gate 		return (0);
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	if (subcl == PCI_MASS_IDE) {
11857c478bd9Sstevel@tonic-gate 		return (1);
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	if (subcl != PCI_MASS_OTHER && subcl != PCI_MASS_SATA) {
11897c478bd9Sstevel@tonic-gate 		return (0);
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	entry = &ide_other[0];
11937c478bd9Sstevel@tonic-gate 	while (entry->venid) {
11947c478bd9Sstevel@tonic-gate 		if (entry->venid == venid && entry->devid == devid)
11957c478bd9Sstevel@tonic-gate 			return (1);
11967c478bd9Sstevel@tonic-gate 		entry++;
11977c478bd9Sstevel@tonic-gate 	}
11987c478bd9Sstevel@tonic-gate 	return (check_pciide_prop(revid, venid, devid, subvenid, subdevid));
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate static int
12027c478bd9Sstevel@tonic-gate is_display(uint_t classcode)
12037c478bd9Sstevel@tonic-gate {
12047c478bd9Sstevel@tonic-gate 	static uint_t disp_classes[] = {
12057c478bd9Sstevel@tonic-gate 		0x000100,
12067c478bd9Sstevel@tonic-gate 		0x030000,
12077c478bd9Sstevel@tonic-gate 		0x030001
12087c478bd9Sstevel@tonic-gate 	};
12097c478bd9Sstevel@tonic-gate 	int i, nclasses = sizeof (disp_classes) / sizeof (uint_t);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	for (i = 0; i < nclasses; i++) {
12127c478bd9Sstevel@tonic-gate 		if (classcode == disp_classes[i])
12137c478bd9Sstevel@tonic-gate 			return (1);
12147c478bd9Sstevel@tonic-gate 	}
12157c478bd9Sstevel@tonic-gate 	return (0);
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate 
1218bd87be88Ssethg static void
1219bd87be88Ssethg add_undofix_entry(uint8_t bus, uint8_t dev, uint8_t fn,
1220bd87be88Ssethg     void (*undofn)(uint8_t, uint8_t, uint8_t))
1221bd87be88Ssethg {
1222bd87be88Ssethg 	struct pci_fixundo *newundo;
1223bd87be88Ssethg 
1224bd87be88Ssethg 	newundo = kmem_alloc(sizeof (struct pci_fixundo), KM_SLEEP);
1225bd87be88Ssethg 
1226bd87be88Ssethg 	/*
1227bd87be88Ssethg 	 * Adding an item to this list means that we must turn its NMIENABLE
1228bd87be88Ssethg 	 * bit back on at a later time.
1229bd87be88Ssethg 	 */
1230bd87be88Ssethg 	newundo->bus = bus;
1231bd87be88Ssethg 	newundo->dev = dev;
1232bd87be88Ssethg 	newundo->fn = fn;
1233bd87be88Ssethg 	newundo->undofn = undofn;
1234bd87be88Ssethg 	newundo->next = undolist;
1235bd87be88Ssethg 
1236bd87be88Ssethg 	/* add to the undo list in LIFO order */
1237bd87be88Ssethg 	undolist = newundo;
1238bd87be88Ssethg }
1239bd87be88Ssethg 
1240bd87be88Ssethg void
1241bd87be88Ssethg add_pci_fixes(void)
1242bd87be88Ssethg {
1243bd87be88Ssethg 	int i;
1244bd87be88Ssethg 
1245bd87be88Ssethg 	for (i = 0; i <= pci_bios_nbus; i++) {
1246bd87be88Ssethg 		/*
1247bd87be88Ssethg 		 * For each bus, apply needed fixes to the appropriate devices.
1248bd87be88Ssethg 		 * This must be done before the main enumeration loop because
1249bd87be88Ssethg 		 * some fixes must be applied to devices normally encountered
1250bd87be88Ssethg 		 * later in the pci scan (e.g. if a fix to device 7 must be
1251bd87be88Ssethg 		 * applied before scanning device 6, applying fixes in the
1252bd87be88Ssethg 		 * normal enumeration loop would obviously be too late).
1253bd87be88Ssethg 		 */
1254bd87be88Ssethg 		enumerate_bus_devs(i, CONFIG_FIX);
1255bd87be88Ssethg 	}
1256bd87be88Ssethg }
1257bd87be88Ssethg 
1258bd87be88Ssethg void
1259bd87be88Ssethg undo_pci_fixes(void)
1260bd87be88Ssethg {
1261bd87be88Ssethg 	struct pci_fixundo *nextundo;
1262bd87be88Ssethg 	uint8_t bus, dev, fn;
1263bd87be88Ssethg 
1264bd87be88Ssethg 	/*
1265bd87be88Ssethg 	 * All fixes in the undo list are performed unconditionally.  Future
1266bd87be88Ssethg 	 * fixes may require selective undo.
1267bd87be88Ssethg 	 */
1268bd87be88Ssethg 	while (undolist != NULL) {
1269bd87be88Ssethg 
1270bd87be88Ssethg 		bus = undolist->bus;
1271bd87be88Ssethg 		dev = undolist->dev;
1272bd87be88Ssethg 		fn = undolist->fn;
1273bd87be88Ssethg 
1274bd87be88Ssethg 		(*(undolist->undofn))(bus, dev, fn);
1275bd87be88Ssethg 
1276bd87be88Ssethg 		nextundo = undolist->next;
1277bd87be88Ssethg 		kmem_free(undolist, sizeof (struct pci_fixundo));
1278bd87be88Ssethg 		undolist = nextundo;
1279bd87be88Ssethg 	}
1280bd87be88Ssethg }
1281bd87be88Ssethg 
1282bd87be88Ssethg static void
1283bd87be88Ssethg undo_amd8111_pci_fix(uint8_t bus, uint8_t dev, uint8_t fn)
1284bd87be88Ssethg {
1285bd87be88Ssethg 	uint8_t val8;
1286bd87be88Ssethg 
1287bd87be88Ssethg 	val8 = pci_getb(bus, dev, fn, LPC_IO_CONTROL_REG_1);
1288bd87be88Ssethg 	/*
1289bd87be88Ssethg 	 * The NMIONERR bit is turned back on to allow the SMM BIOS
1290bd87be88Ssethg 	 * to handle more critical PCI errors (e.g. PERR#).
1291bd87be88Ssethg 	 */
1292bd87be88Ssethg 	val8 |= AMD8111_ENABLENMI;
1293bd87be88Ssethg 	pci_putb(bus, dev, fn, LPC_IO_CONTROL_REG_1, val8);
1294bd87be88Ssethg }
1295bd87be88Ssethg 
1296bd87be88Ssethg static void
1297bd87be88Ssethg pci_fix_amd8111(uint8_t bus, uint8_t dev, uint8_t fn)
1298bd87be88Ssethg {
1299bd87be88Ssethg 	uint8_t val8;
1300bd87be88Ssethg 
1301bd87be88Ssethg 	val8 = pci_getb(bus, dev, fn, LPC_IO_CONTROL_REG_1);
1302bd87be88Ssethg 
1303bd87be88Ssethg 	if ((val8 & AMD8111_ENABLENMI) == 0)
1304bd87be88Ssethg 		return;
1305bd87be88Ssethg 
1306bd87be88Ssethg 	/*
1307bd87be88Ssethg 	 * We reset NMIONERR in the LPC because master-abort on the PCI
1308bd87be88Ssethg 	 * bridge side of the 8111 will cause NMI, which might cause SMI,
1309bd87be88Ssethg 	 * which sometimes prevents all devices from being enumerated.
1310bd87be88Ssethg 	 */
1311bd87be88Ssethg 	val8 &= ~AMD8111_ENABLENMI;
1312bd87be88Ssethg 
1313bd87be88Ssethg 	pci_putb(bus, dev, fn, LPC_IO_CONTROL_REG_1, val8);
1314bd87be88Ssethg 
1315bd87be88Ssethg 	add_undofix_entry(bus, dev, fn, undo_amd8111_pci_fix);
1316bd87be88Ssethg }
1317bd87be88Ssethg 
1318*05f867c3Sgs static void
1319bd87be88Ssethg process_devfunc(uchar_t bus, uchar_t dev, uchar_t func, uchar_t header,
13207c478bd9Sstevel@tonic-gate     ushort_t vendorid, int config_op)
13217c478bd9Sstevel@tonic-gate {
13227c478bd9Sstevel@tonic-gate 	char nodename[32], unitaddr[5];
13237c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
1324c8589f13Ssethg 	uchar_t basecl, subcl, progcl, intr, revid;
13257c478bd9Sstevel@tonic-gate 	ushort_t subvenid, subdevid, status;
132670025d76Sjohnny 	ushort_t slot_num;
13277c478bd9Sstevel@tonic-gate 	uint_t classcode, revclass;
13288d483882Smlf 	int reprogram = 0, pciide = 0;
13297c478bd9Sstevel@tonic-gate 	int power[2] = {1, 1};
133070025d76Sjohnny 	int pciex = 0;
133170025d76Sjohnny 	ushort_t is_pci_bridge = 0;
1332*05f867c3Sgs 	struct pci_devfunc *devlist = NULL, *entry = NULL;
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	ushort_t deviceid = pci_getw(bus, dev, func, PCI_CONF_DEVID);
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	switch (header & PCI_HEADER_TYPE_M) {
13377c478bd9Sstevel@tonic-gate 	case PCI_HEADER_ZERO:
13387c478bd9Sstevel@tonic-gate 		subvenid = pci_getw(bus, dev, func, PCI_CONF_SUBVENID);
13397c478bd9Sstevel@tonic-gate 		subdevid = pci_getw(bus, dev, func, PCI_CONF_SUBSYSID);
13407c478bd9Sstevel@tonic-gate 		break;
13417c478bd9Sstevel@tonic-gate 	case PCI_HEADER_CARDBUS:
13427c478bd9Sstevel@tonic-gate 		subvenid = pci_getw(bus, dev, func, PCI_CBUS_SUBVENID);
13437c478bd9Sstevel@tonic-gate 		subdevid = pci_getw(bus, dev, func, PCI_CBUS_SUBSYSID);
1344*05f867c3Sgs 		/* Record the # of cardbus bridges found on the bus */
1345*05f867c3Sgs 		if (config_op == CONFIG_INFO)
1346*05f867c3Sgs 			pci_bus_res[bus].num_cbb++;
13477c478bd9Sstevel@tonic-gate 		break;
13487c478bd9Sstevel@tonic-gate 	default:
13497c478bd9Sstevel@tonic-gate 		subvenid = 0;
13507c478bd9Sstevel@tonic-gate 		subdevid = 0;
13517c478bd9Sstevel@tonic-gate 		break;
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 
1354bd87be88Ssethg 	if (config_op == CONFIG_FIX) {
1355bd87be88Ssethg 		if (vendorid == VENID_AMD && deviceid == DEVID_AMD8111_LPC) {
1356bd87be88Ssethg 			pci_fix_amd8111(bus, dev, func);
1357bd87be88Ssethg 		}
1358*05f867c3Sgs 		return;
1359bd87be88Ssethg 	}
1360bd87be88Ssethg 
13617c478bd9Sstevel@tonic-gate 	/* XXX should be use generic names? derive from class? */
13627c478bd9Sstevel@tonic-gate 	revclass = pci_getl(bus, dev, func, PCI_CONF_REVID);
13637c478bd9Sstevel@tonic-gate 	classcode = revclass >> 8;
13647c478bd9Sstevel@tonic-gate 	revid = revclass & 0xff;
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	/* figure out if this is pci-ide */
13677c478bd9Sstevel@tonic-gate 	basecl = classcode >> 16;
13687c478bd9Sstevel@tonic-gate 	subcl = (classcode >> 8) & 0xff;
1369c8589f13Ssethg 	progcl = classcode & 0xff;
13707c478bd9Sstevel@tonic-gate 
13718d483882Smlf 
13728d483882Smlf 	if (is_display(classcode))
13737c478bd9Sstevel@tonic-gate 		(void) snprintf(nodename, sizeof (nodename), "display");
13747c478bd9Sstevel@tonic-gate 	else if (subvenid != 0)
13757c478bd9Sstevel@tonic-gate 		(void) snprintf(nodename, sizeof (nodename),
13767c478bd9Sstevel@tonic-gate 		    "pci%x,%x", subvenid, subdevid);
13777c478bd9Sstevel@tonic-gate 	else
13787c478bd9Sstevel@tonic-gate 		(void) snprintf(nodename, sizeof (nodename),
13797c478bd9Sstevel@tonic-gate 		    "pci%x,%x", vendorid, deviceid);
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	/* make sure parent bus dip has been created */
13827c478bd9Sstevel@tonic-gate 	if (pci_bus_res[bus].dip == NULL) {
13837c478bd9Sstevel@tonic-gate 		create_root_bus_dip(bus);
13847c478bd9Sstevel@tonic-gate 	}
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(pci_bus_res[bus].dip, nodename,
13877c478bd9Sstevel@tonic-gate 	    DEVI_SID_NODEID, &dip);
13887c478bd9Sstevel@tonic-gate 
138900d0963fSdilpreet 	if (check_if_device_is_pciex(dip, bus, dev, func, &slot_num,
139000d0963fSdilpreet 	    &is_pci_bridge) == B_TRUE)
139100d0963fSdilpreet 		pciex = 1;
139200d0963fSdilpreet 
13937c478bd9Sstevel@tonic-gate 	/* add properties */
13947c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id", deviceid);
13957c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id", vendorid);
13967c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "revision-id", revid);
13977c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
13987c478bd9Sstevel@tonic-gate 	    "class-code", classcode);
13997c478bd9Sstevel@tonic-gate 	if (func == 0)
14007c478bd9Sstevel@tonic-gate 		(void) snprintf(unitaddr, sizeof (unitaddr), "%x", dev);
14017c478bd9Sstevel@tonic-gate 	else
14027c478bd9Sstevel@tonic-gate 		(void) snprintf(unitaddr, sizeof (unitaddr),
14037c478bd9Sstevel@tonic-gate 		    "%x,%x", dev, func);
14047c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
14057c478bd9Sstevel@tonic-gate 	    "unit-address", unitaddr);
14067c478bd9Sstevel@tonic-gate 
1407ebf3afa8Sdmick 	/* add device_type for display nodes */
1408ebf3afa8Sdmick 	if (is_display(classcode)) {
1409ebf3afa8Sdmick 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1410ebf3afa8Sdmick 		    "device_type", "display");
1411ebf3afa8Sdmick 	}
14127c478bd9Sstevel@tonic-gate 	/* add special stuff for header type */
14137c478bd9Sstevel@tonic-gate 	if ((header & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) {
14147c478bd9Sstevel@tonic-gate 		uchar_t mingrant = pci_getb(bus, dev, func, PCI_CONF_MIN_G);
14157c478bd9Sstevel@tonic-gate 		uchar_t maxlatency = pci_getb(bus, dev, func, PCI_CONF_MAX_L);
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 		if (subvenid != 0) {
14187c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
14197c478bd9Sstevel@tonic-gate 			    "subsystem-id", subdevid);
14207c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
14217c478bd9Sstevel@tonic-gate 			    "subsystem-vendor-id", subvenid);
14227c478bd9Sstevel@tonic-gate 		}
142370025d76Sjohnny 		if (!pciex)
142470025d76Sjohnny 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
142570025d76Sjohnny 			    "min-grant", mingrant);
142670025d76Sjohnny 		if (!pciex)
142770025d76Sjohnny 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
142870025d76Sjohnny 			    "max-latency", maxlatency);
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	/* interrupt, record if not 0 */
14327c478bd9Sstevel@tonic-gate 	intr = pci_getb(bus, dev, func, PCI_CONF_IPIN);
14337c478bd9Sstevel@tonic-gate 	if (intr != 0)
14347c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
14357c478bd9Sstevel@tonic-gate 		    "interrupts", intr);
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	/*
14387c478bd9Sstevel@tonic-gate 	 * Add support for 133 mhz pci eventually
14397c478bd9Sstevel@tonic-gate 	 */
14407c478bd9Sstevel@tonic-gate 	status = pci_getw(bus, dev, func, PCI_CONF_STAT);
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
14437c478bd9Sstevel@tonic-gate 	    "devsel-speed", (status & PCI_STAT_DEVSELT) >> 9);
144470025d76Sjohnny 	if (!pciex && (status & PCI_STAT_FBBC))
14457c478bd9Sstevel@tonic-gate 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
14467c478bd9Sstevel@tonic-gate 		    "fast-back-to-back");
144770025d76Sjohnny 	if (!pciex && (status & PCI_STAT_66MHZ))
14487c478bd9Sstevel@tonic-gate 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
14497c478bd9Sstevel@tonic-gate 		    "66mhz-capable");
14507c478bd9Sstevel@tonic-gate 	if (status & PCI_STAT_UDF)
14517c478bd9Sstevel@tonic-gate 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
14527c478bd9Sstevel@tonic-gate 		    "udf-supported");
1453d57b3b3dSprasad 	if (pciex && slot_num) {
145470025d76Sjohnny 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
145570025d76Sjohnny 		    "physical-slot#", slot_num);
1456d57b3b3dSprasad 		if (!is_pci_bridge)
1457d57b3b3dSprasad 			pciex_slot_names_prop(dip, slot_num);
1458d57b3b3dSprasad 	}
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
14617c478bd9Sstevel@tonic-gate 	    "power-consumption", power, 2);
14627c478bd9Sstevel@tonic-gate 
146370025d76Sjohnny 	if ((basecl == PCI_CLASS_BRIDGE) && (subcl == PCI_BRIDGE_PCI))
146470025d76Sjohnny 		add_ppb_props(dip, bus, dev, func, pciex);
1465*05f867c3Sgs 	else {
1466*05f867c3Sgs 		/*
1467*05f867c3Sgs 		 * Record the non-PPB devices on the bus for possible
1468*05f867c3Sgs 		 * reprogramming at 2nd bus enumeration.
1469*05f867c3Sgs 		 * Note: PPB reprogramming is done in fix_ppb_res()
1470*05f867c3Sgs 		 */
1471*05f867c3Sgs 		devlist = (struct pci_devfunc *)pci_bus_res[bus].privdata;
1472*05f867c3Sgs 		entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
1473*05f867c3Sgs 		entry->dip = dip;
1474*05f867c3Sgs 		entry->dev = dev;
1475*05f867c3Sgs 		entry->func = func;
1476*05f867c3Sgs 		entry->next = devlist;
1477*05f867c3Sgs 		pci_bus_res[bus].privdata = entry;
1478*05f867c3Sgs 	}
147970025d76Sjohnny 
1480c8589f13Ssethg 	if (config_op == CONFIG_INFO &&
1481c8589f13Ssethg 	    IS_CLASS_IOAPIC(basecl, subcl, progcl)) {
1482c8589f13Ssethg 		create_ioapic_node(bus, dev, func, vendorid, deviceid);
1483c8589f13Ssethg 	}
1484c8589f13Ssethg 
148570025d76Sjohnny 	/* check for ck8-04 based PCI ISA bridge only */
148670025d76Sjohnny 	if (NVIDIA_IS_LPC_BRIDGE(vendorid, deviceid) && (dev == 1) &&
148770025d76Sjohnny 	    (func == 0))
14888a5a0d1eSanish 		add_nvidia_isa_bridge_props(dip, bus, dev, func);
148970025d76Sjohnny 
149070025d76Sjohnny 	if (pciex && is_pci_bridge)
149170025d76Sjohnny 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
149270025d76Sjohnny 		    (char *)"PCIe-PCI bridge");
149370025d76Sjohnny 	else
149470025d76Sjohnny 		add_model_prop(dip, classcode);
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	add_compatible(dip, subvenid, subdevid, vendorid, deviceid,
149770025d76Sjohnny 	    revid, classcode, pciex);
14988d483882Smlf 
14998d483882Smlf 	/*
15008d483882Smlf 	 * See if this device is a controller that advertises
15018d483882Smlf 	 * itself to be a standard ATA task file controller, or one that
15028d483882Smlf 	 * has been hard coded.
15038d483882Smlf 	 *
15048d483882Smlf 	 * If it is, check if any other higher precedence driver listed in
15058d483882Smlf 	 * driver_aliases will claim the node by calling
15068d483882Smlf 	 * ddi_compatibile_driver_major.  If so, clear pciide and do not
15078d483882Smlf 	 * create a pci-ide node or any other special handling.
15088d483882Smlf 	 *
15098d483882Smlf 	 * If another driver does not bind, set the node name to pci-ide
15108d483882Smlf 	 * and then let the special pci-ide handling for registers and
15118d483882Smlf 	 * child pci-ide nodes proceed below.
15128d483882Smlf 	 */
15138d483882Smlf 	if (is_pciide(basecl, subcl, revid, vendorid, deviceid,
15148d483882Smlf 	    subvenid, subdevid) == 1) {
15158d483882Smlf 		if (ddi_compatible_driver_major(dip, NULL) == (major_t)-1) {
15168d483882Smlf 			(void) ndi_devi_set_nodename(dip, "pci-ide", 0);
15178d483882Smlf 			pciide = 1;
15188d483882Smlf 		}
15198d483882Smlf 	}
15208d483882Smlf 
15217c478bd9Sstevel@tonic-gate 	reprogram = add_reg_props(dip, bus, dev, func, config_op, pciide);
15227c478bd9Sstevel@tonic-gate 	(void) ndi_devi_bind_driver(dip, 0);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	/* special handling for pci-ide */
15257c478bd9Sstevel@tonic-gate 	if (pciide) {
15267c478bd9Sstevel@tonic-gate 		dev_info_t *cdip;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 		/*
15297c478bd9Sstevel@tonic-gate 		 * Create properties specified by P1275 Working Group
15307c478bd9Sstevel@tonic-gate 		 * Proposal #414 Version 1
15317c478bd9Sstevel@tonic-gate 		 */
15327c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
15337c478bd9Sstevel@tonic-gate 		    "device_type", "pci-ide");
15347c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
15357c478bd9Sstevel@tonic-gate 		    "#address-cells", 1);
15367c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
15377c478bd9Sstevel@tonic-gate 		    "#size-cells", 0);
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 		/* allocate two child nodes */
15407c478bd9Sstevel@tonic-gate 		ndi_devi_alloc_sleep(dip, "ide",
1541fa9e4066Sahrens 		    (pnode_t)DEVI_SID_NODEID, &cdip);
15427c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
15437c478bd9Sstevel@tonic-gate 		    "reg", 0);
15447c478bd9Sstevel@tonic-gate 		(void) ndi_devi_bind_driver(cdip, 0);
15457c478bd9Sstevel@tonic-gate 		ndi_devi_alloc_sleep(dip, "ide",
1546fa9e4066Sahrens 		    (pnode_t)DEVI_SID_NODEID, &cdip);
15477c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
15487c478bd9Sstevel@tonic-gate 		    "reg", 1);
15497c478bd9Sstevel@tonic-gate 		(void) ndi_devi_bind_driver(cdip, 0);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 		reprogram = 0;	/* don't reprogram pci-ide bridge */
15527c478bd9Sstevel@tonic-gate 	}
15537c478bd9Sstevel@tonic-gate 
1554*05f867c3Sgs 	if (reprogram && (entry != NULL))
1555*05f867c3Sgs 		entry->reprogram = B_TRUE;
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate /*
15597c478bd9Sstevel@tonic-gate  * Set the compatible property to a value compliant with
15607c478bd9Sstevel@tonic-gate  * rev 2.1 of the IEEE1275 PCI binding.
156170025d76Sjohnny  * (Also used for PCI-Express devices).
15627c478bd9Sstevel@tonic-gate  *
15637c478bd9Sstevel@tonic-gate  *   pciVVVV,DDDD.SSSS.ssss.RR	(0)
15647c478bd9Sstevel@tonic-gate  *   pciVVVV,DDDD.SSSS.ssss	(1)
15657c478bd9Sstevel@tonic-gate  *   pciSSSS,ssss		(2)
15667c478bd9Sstevel@tonic-gate  *   pciVVVV,DDDD.RR		(3)
15677c478bd9Sstevel@tonic-gate  *   pciVVVV,DDDD		(4)
15687c478bd9Sstevel@tonic-gate  *   pciclass,CCSSPP		(5)
15697c478bd9Sstevel@tonic-gate  *   pciclass,CCSS		(6)
15707c478bd9Sstevel@tonic-gate  *
15717c478bd9Sstevel@tonic-gate  * The Subsystem (SSSS) forms are not inserted if
15727c478bd9Sstevel@tonic-gate  * subsystem-vendor-id is 0.
15737c478bd9Sstevel@tonic-gate  *
157470025d76Sjohnny  * NOTE: For PCI-Express devices "pci" is replaced with "pciex" in 0-6 above
157570025d76Sjohnny  * property 2 is not created as per "1275 bindings for PCI Express Interconnect"
157670025d76Sjohnny  *
15777c478bd9Sstevel@tonic-gate  * Set with setprop and \x00 between each
15787c478bd9Sstevel@tonic-gate  * to generate the encoded string array form.
15797c478bd9Sstevel@tonic-gate  */
15807c478bd9Sstevel@tonic-gate void
15817c478bd9Sstevel@tonic-gate add_compatible(dev_info_t *dip, ushort_t subvenid, ushort_t subdevid,
158270025d76Sjohnny     ushort_t vendorid, ushort_t deviceid, uchar_t revid, uint_t classcode,
158370025d76Sjohnny     int pciex)
15847c478bd9Sstevel@tonic-gate {
158570025d76Sjohnny 	int i = 0;
158670025d76Sjohnny 	int size = COMPAT_BUFSIZE;
158770025d76Sjohnny 	char *compat[13];
15887c478bd9Sstevel@tonic-gate 	char *buf, *curr;
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	curr = buf = kmem_alloc(size, KM_SLEEP);
15917c478bd9Sstevel@tonic-gate 
159270025d76Sjohnny 	if (pciex) {
159370025d76Sjohnny 		if (subvenid) {
159470025d76Sjohnny 			compat[i++] = curr;	/* form 0 */
159570025d76Sjohnny 			(void) snprintf(curr, size, "pciex%x,%x.%x.%x.%x",
159670025d76Sjohnny 			    vendorid, deviceid, subvenid, subdevid, revid);
159770025d76Sjohnny 			size -= strlen(curr) + 1;
159870025d76Sjohnny 			curr += strlen(curr) + 1;
159970025d76Sjohnny 
160070025d76Sjohnny 			compat[i++] = curr;	/* form 1 */
160170025d76Sjohnny 			(void) snprintf(curr, size, "pciex%x,%x.%x.%x",
160270025d76Sjohnny 			    vendorid, deviceid, subvenid, subdevid);
160370025d76Sjohnny 			size -= strlen(curr) + 1;
160470025d76Sjohnny 			curr += strlen(curr) + 1;
160570025d76Sjohnny 
160670025d76Sjohnny 		}
160770025d76Sjohnny 		compat[i++] = curr;	/* form 3 */
160870025d76Sjohnny 		(void) snprintf(curr, size, "pciex%x,%x.%x",
160970025d76Sjohnny 		    vendorid, deviceid, revid);
161070025d76Sjohnny 		size -= strlen(curr) + 1;
161170025d76Sjohnny 		curr += strlen(curr) + 1;
161270025d76Sjohnny 
161370025d76Sjohnny 		compat[i++] = curr;	/* form 4 */
161470025d76Sjohnny 		(void) snprintf(curr, size, "pciex%x,%x", vendorid, deviceid);
161570025d76Sjohnny 		size -= strlen(curr) + 1;
161670025d76Sjohnny 		curr += strlen(curr) + 1;
161770025d76Sjohnny 
161870025d76Sjohnny 		compat[i++] = curr;	/* form 5 */
161970025d76Sjohnny 		(void) snprintf(curr, size, "pciexclass,%06x", classcode);
162070025d76Sjohnny 		size -= strlen(curr) + 1;
162170025d76Sjohnny 		curr += strlen(curr) + 1;
162270025d76Sjohnny 
162370025d76Sjohnny 		compat[i++] = curr;	/* form 6 */
162470025d76Sjohnny 		(void) snprintf(curr, size, "pciexclass,%04x",
162570025d76Sjohnny 		    (classcode >> 8));
162670025d76Sjohnny 		size -= strlen(curr) + 1;
162770025d76Sjohnny 		curr += strlen(curr) + 1;
162870025d76Sjohnny 	}
162970025d76Sjohnny 
16307c478bd9Sstevel@tonic-gate 	if (subvenid) {
16317c478bd9Sstevel@tonic-gate 		compat[i++] = curr;	/* form 0 */
16327c478bd9Sstevel@tonic-gate 		(void) snprintf(curr, size, "pci%x,%x.%x.%x.%x",
16337c478bd9Sstevel@tonic-gate 		    vendorid, deviceid, subvenid, subdevid, revid);
16347c478bd9Sstevel@tonic-gate 		size -= strlen(curr) + 1;
16357c478bd9Sstevel@tonic-gate 		curr += strlen(curr) + 1;
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 		compat[i++] = curr;	/* form 1 */
16387c478bd9Sstevel@tonic-gate 		(void) snprintf(curr, size, "pci%x,%x.%x.%x",
16397c478bd9Sstevel@tonic-gate 		    vendorid, deviceid, subvenid, subdevid);
16407c478bd9Sstevel@tonic-gate 		size -= strlen(curr) + 1;
16417c478bd9Sstevel@tonic-gate 		curr += strlen(curr) + 1;
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 		compat[i++] = curr;	/* form 2 */
164470025d76Sjohnny 		(void) snprintf(curr, size, "pci%x,%x", subvenid, subdevid);
16457c478bd9Sstevel@tonic-gate 		size -= strlen(curr) + 1;
16467c478bd9Sstevel@tonic-gate 		curr += strlen(curr) + 1;
16477c478bd9Sstevel@tonic-gate 	}
16487c478bd9Sstevel@tonic-gate 	compat[i++] = curr;	/* form 3 */
16497c478bd9Sstevel@tonic-gate 	(void) snprintf(curr, size, "pci%x,%x.%x", vendorid, deviceid, revid);
16507c478bd9Sstevel@tonic-gate 	size -= strlen(curr) + 1;
16517c478bd9Sstevel@tonic-gate 	curr += strlen(curr) + 1;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	compat[i++] = curr;	/* form 4 */
16547c478bd9Sstevel@tonic-gate 	(void) snprintf(curr, size, "pci%x,%x", vendorid, deviceid);
16557c478bd9Sstevel@tonic-gate 	size -= strlen(curr) + 1;
16567c478bd9Sstevel@tonic-gate 	curr += strlen(curr) + 1;
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	compat[i++] = curr;	/* form 5 */
16597c478bd9Sstevel@tonic-gate 	(void) snprintf(curr, size, "pciclass,%06x", classcode);
16607c478bd9Sstevel@tonic-gate 	size -= strlen(curr) + 1;
16617c478bd9Sstevel@tonic-gate 	curr += strlen(curr) + 1;
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	compat[i++] = curr;	/* form 6 */
16647c478bd9Sstevel@tonic-gate 	(void) snprintf(curr, size, "pciclass,%04x", (classcode >> 8));
166570025d76Sjohnny 	size -= strlen(curr) + 1;
166670025d76Sjohnny 	curr += strlen(curr) + 1;
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
16697c478bd9Sstevel@tonic-gate 	    "compatible", compat, i);
16707c478bd9Sstevel@tonic-gate 	kmem_free(buf, COMPAT_BUFSIZE);
16717c478bd9Sstevel@tonic-gate }
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate /*
16747c478bd9Sstevel@tonic-gate  * Adjust the reg properties for a dual channel PCI-IDE device.
16757c478bd9Sstevel@tonic-gate  *
16767c478bd9Sstevel@tonic-gate  * NOTE: don't do anything that changes the order of the hard-decodes
16777c478bd9Sstevel@tonic-gate  * and programmed BARs. The kernel driver depends on these values
16787c478bd9Sstevel@tonic-gate  * being in this order regardless of whether they're for a 'native'
16797c478bd9Sstevel@tonic-gate  * mode BAR or not.
16807c478bd9Sstevel@tonic-gate  */
16817c478bd9Sstevel@tonic-gate /*
16827c478bd9Sstevel@tonic-gate  * config info for pci-ide devices
16837c478bd9Sstevel@tonic-gate  */
16847c478bd9Sstevel@tonic-gate static struct {
16857c478bd9Sstevel@tonic-gate 	uchar_t  native_mask;	/* 0 == 'compatibility' mode, 1 == native */
16867c478bd9Sstevel@tonic-gate 	uchar_t  bar_offset;	/* offset for alt status register */
16877c478bd9Sstevel@tonic-gate 	ushort_t addr;		/* compatibility mode base address */
16887c478bd9Sstevel@tonic-gate 	ushort_t length;	/* number of ports for this BAR */
16897c478bd9Sstevel@tonic-gate } pciide_bar[] = {
16907c478bd9Sstevel@tonic-gate 	{ 0x01, 0, 0x1f0, 8 },	/* primary lower BAR */
16917c478bd9Sstevel@tonic-gate 	{ 0x01, 2, 0x3f6, 1 },	/* primary upper BAR */
16927c478bd9Sstevel@tonic-gate 	{ 0x04, 0, 0x170, 8 },	/* secondary lower BAR */
16937c478bd9Sstevel@tonic-gate 	{ 0x04, 2, 0x376, 1 }	/* secondary upper BAR */
16947c478bd9Sstevel@tonic-gate };
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate static int
16977c478bd9Sstevel@tonic-gate pciIdeAdjustBAR(uchar_t progcl, int index, uint_t *basep, uint_t *lenp)
16987c478bd9Sstevel@tonic-gate {
16997c478bd9Sstevel@tonic-gate 	int hard_decode = 0;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	/*
17027c478bd9Sstevel@tonic-gate 	 * Adjust the base and len for the BARs of the PCI-IDE
17037c478bd9Sstevel@tonic-gate 	 * device's primary and secondary controllers. The first
17047c478bd9Sstevel@tonic-gate 	 * two BARs are for the primary controller and the next
17057c478bd9Sstevel@tonic-gate 	 * two BARs are for the secondary controller. The fifth
17067c478bd9Sstevel@tonic-gate 	 * and sixth bars are never adjusted.
17077c478bd9Sstevel@tonic-gate 	 */
17087c478bd9Sstevel@tonic-gate 	if (index >= 0 && index <= 3) {
17097c478bd9Sstevel@tonic-gate 		*lenp = pciide_bar[index].length;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 		if (progcl & pciide_bar[index].native_mask) {
17127c478bd9Sstevel@tonic-gate 			*basep += pciide_bar[index].bar_offset;
17137c478bd9Sstevel@tonic-gate 		} else {
17147c478bd9Sstevel@tonic-gate 			*basep = pciide_bar[index].addr;
17157c478bd9Sstevel@tonic-gate 			hard_decode = 1;
17167c478bd9Sstevel@tonic-gate 		}
17177c478bd9Sstevel@tonic-gate 	}
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	/*
17207c478bd9Sstevel@tonic-gate 	 * if either base or len is zero make certain both are zero
17217c478bd9Sstevel@tonic-gate 	 */
17227c478bd9Sstevel@tonic-gate 	if (*basep == 0 || *lenp == 0) {
17237c478bd9Sstevel@tonic-gate 		*basep = 0;
17247c478bd9Sstevel@tonic-gate 		*lenp = 0;
17257c478bd9Sstevel@tonic-gate 		hard_decode = 0;
17267c478bd9Sstevel@tonic-gate 	}
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	return (hard_decode);
17297c478bd9Sstevel@tonic-gate }
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate /*
17337c478bd9Sstevel@tonic-gate  * Add the "reg" and "assigned-addresses" property
17347c478bd9Sstevel@tonic-gate  */
17357c478bd9Sstevel@tonic-gate static int
17367c478bd9Sstevel@tonic-gate add_reg_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
17377c478bd9Sstevel@tonic-gate     int config_op, int pciide)
17387c478bd9Sstevel@tonic-gate {
17397c478bd9Sstevel@tonic-gate 	uchar_t baseclass, subclass, progclass, header;
17407c478bd9Sstevel@tonic-gate 	ushort_t bar_sz;
17417c478bd9Sstevel@tonic-gate 	uint_t value = 0, len, devloc;
17427c478bd9Sstevel@tonic-gate 	uint_t base, base_hi, type;
17437c478bd9Sstevel@tonic-gate 	ushort_t offset, end;
17447c478bd9Sstevel@tonic-gate 	int max_basereg, j, reprogram = 0;
17457c478bd9Sstevel@tonic-gate 	uint_t phys_hi;
17467c478bd9Sstevel@tonic-gate 	struct memlist **io_res, **mres, **mem_res, **pmem_res;
1747*05f867c3Sgs 	struct memlist **io_res_used, **mres_used;
1748*05f867c3Sgs 	struct memlist **mem_res_used, **pmem_res_used;
1749*05f867c3Sgs 	uchar_t res_bus;
175046e9e839Smyers 	uint16_t cmd_reg;
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 	pci_regspec_t regs[16] = {{0}};
17537c478bd9Sstevel@tonic-gate 	pci_regspec_t assigned[15] = {{0}};
1754ebf3afa8Sdmick 	int nreg, nasgn, enable = 0;
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	io_res = &pci_bus_res[bus].io_ports;
1757*05f867c3Sgs 	io_res_used = &pci_bus_res[bus].io_ports_used;
17587c478bd9Sstevel@tonic-gate 	mem_res = &pci_bus_res[bus].mem_space;
1759*05f867c3Sgs 	mem_res_used = &pci_bus_res[bus].mem_space_used;
1760*05f867c3Sgs 	if (bus == 0) {	/* for bus 0, there is only mem_space */
17617c478bd9Sstevel@tonic-gate 		pmem_res = mem_res;
1762*05f867c3Sgs 		pmem_res_used = mem_res_used;
1763*05f867c3Sgs 	} else {
17647c478bd9Sstevel@tonic-gate 		pmem_res = &pci_bus_res[bus].pmem_space;
1765*05f867c3Sgs 		pmem_res_used = &pci_bus_res[bus].pmem_space_used;
1766*05f867c3Sgs 	}
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 	devloc = (uint_t)bus << 16 | (uint_t)dev << 11 | (uint_t)func << 8;
17697c478bd9Sstevel@tonic-gate 	regs[0].pci_phys_hi = devloc;
17707c478bd9Sstevel@tonic-gate 	nreg = 1;	/* rest of regs[0] is all zero */
17717c478bd9Sstevel@tonic-gate 	nasgn = 0;
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	baseclass = pci_getb(bus, dev, func, PCI_CONF_BASCLASS);
17747c478bd9Sstevel@tonic-gate 	subclass = pci_getb(bus, dev, func, PCI_CONF_SUBCLASS);
17757c478bd9Sstevel@tonic-gate 	progclass = pci_getb(bus, dev, func, PCI_CONF_PROGCLASS);
17767c478bd9Sstevel@tonic-gate 	header = pci_getb(bus, dev, func, PCI_CONF_HEADER) & PCI_HEADER_TYPE_M;
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	switch (header) {
17797c478bd9Sstevel@tonic-gate 	case PCI_HEADER_ZERO:
17807c478bd9Sstevel@tonic-gate 		max_basereg = PCI_BASE_NUM;
17817c478bd9Sstevel@tonic-gate 		break;
17827c478bd9Sstevel@tonic-gate 	case PCI_HEADER_PPB:
17837c478bd9Sstevel@tonic-gate 		max_basereg = PCI_BCNF_BASE_NUM;
17847c478bd9Sstevel@tonic-gate 		break;
17857c478bd9Sstevel@tonic-gate 	case PCI_HEADER_CARDBUS:
17867c478bd9Sstevel@tonic-gate 		max_basereg = PCI_CBUS_BASE_NUM;
17877c478bd9Sstevel@tonic-gate 		break;
17887c478bd9Sstevel@tonic-gate 	default:
17897c478bd9Sstevel@tonic-gate 		max_basereg = 0;
17907c478bd9Sstevel@tonic-gate 		break;
17917c478bd9Sstevel@tonic-gate 	}
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	/*
17947c478bd9Sstevel@tonic-gate 	 * Create the register property by saving the current
17958d34f104Smyers 	 * value of the base register. Write 0xffffffff to the
17968d34f104Smyers 	 * base register.  Read the value back to determine the
17978d34f104Smyers 	 * required size of the address space.  Restore the base
17988d34f104Smyers 	 * register contents.
17998d34f104Smyers 	 *
18008d34f104Smyers 	 * Do not disable I/O and memory access; this isn't necessary
18018d34f104Smyers 	 * since no driver is yet attached to this device, and disabling
18028d34f104Smyers 	 * I/O and memory access has the side-effect of disabling PCI-PCI
18038d34f104Smyers 	 * bridge mappings, which makes the bridge transparent to secondary-
18048d34f104Smyers 	 * bus activity (see sections 4.1-4.3 of the PCI-PCI Bridge
18058d34f104Smyers 	 * Spec V1.2).
18067c478bd9Sstevel@tonic-gate 	 */
18077c478bd9Sstevel@tonic-gate 	end = PCI_CONF_BASE0 + max_basereg * sizeof (uint_t);
18087c478bd9Sstevel@tonic-gate 	for (j = 0, offset = PCI_CONF_BASE0; offset < end;
18097c478bd9Sstevel@tonic-gate 	    j++, offset += bar_sz) {
18107c478bd9Sstevel@tonic-gate 		int hard_decode = 0;
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 		/* determine the size of the address space */
18137c478bd9Sstevel@tonic-gate 		base = pci_getl(bus, dev, func, offset);
18147c478bd9Sstevel@tonic-gate 		pci_putl(bus, dev, func, offset, 0xffffffff);
18157c478bd9Sstevel@tonic-gate 		value = pci_getl(bus, dev, func, offset);
18167c478bd9Sstevel@tonic-gate 		pci_putl(bus, dev, func, offset, base);
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 		/* construct phys hi,med.lo, size hi, lo */
18197c478bd9Sstevel@tonic-gate 		if ((pciide && j < 4) || (base & PCI_BASE_SPACE_IO)) {
18207c478bd9Sstevel@tonic-gate 			/* i/o space */
18217c478bd9Sstevel@tonic-gate 			bar_sz = PCI_BAR_SZ_32;
18227c478bd9Sstevel@tonic-gate 			value &= PCI_BASE_IO_ADDR_M;
18237c478bd9Sstevel@tonic-gate 			len = ((value ^ (value-1)) + 1) >> 1;
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 			/* XXX Adjust first 4 IDE registers */
18267c478bd9Sstevel@tonic-gate 			if (pciide) {
1827f088817aSyt 				if (subclass != PCI_MASS_IDE)
18287c478bd9Sstevel@tonic-gate 					progclass = (PCI_IDE_IF_NATIVE_PRI |
18297c478bd9Sstevel@tonic-gate 					    PCI_IDE_IF_NATIVE_SEC);
18307c478bd9Sstevel@tonic-gate 				hard_decode = pciIdeAdjustBAR(progclass, j,
18317c478bd9Sstevel@tonic-gate 				    &base, &len);
18327c478bd9Sstevel@tonic-gate 			} else if (value == 0) {
18337c478bd9Sstevel@tonic-gate 				/* skip base regs with size of 0 */
18347c478bd9Sstevel@tonic-gate 				continue;
18357c478bd9Sstevel@tonic-gate 			}
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 			regs[nreg].pci_size_low =
18387c478bd9Sstevel@tonic-gate 			    assigned[nasgn].pci_size_low = len;
18397c478bd9Sstevel@tonic-gate 			if (!hard_decode) {
18407c478bd9Sstevel@tonic-gate 				regs[nreg].pci_phys_hi =
18417c478bd9Sstevel@tonic-gate 				    (PCI_ADDR_IO | devloc) + offset;
18427c478bd9Sstevel@tonic-gate 			} else {
18437c478bd9Sstevel@tonic-gate 				regs[nreg].pci_phys_hi =
18447c478bd9Sstevel@tonic-gate 				    (PCI_RELOCAT_B | PCI_ADDR_IO | devloc) +
18457c478bd9Sstevel@tonic-gate 				    offset;
18467c478bd9Sstevel@tonic-gate 				regs[nreg].pci_phys_low =
18477c478bd9Sstevel@tonic-gate 				    base & PCI_BASE_IO_ADDR_M;
18487c478bd9Sstevel@tonic-gate 			}
18497c478bd9Sstevel@tonic-gate 			assigned[nasgn].pci_phys_hi =
18507c478bd9Sstevel@tonic-gate 			    (PCI_RELOCAT_B | PCI_ADDR_IO | devloc) + offset;
18517c478bd9Sstevel@tonic-gate 			type = base & (~PCI_BASE_IO_ADDR_M);
18527c478bd9Sstevel@tonic-gate 			base &= PCI_BASE_IO_ADDR_M;
1853*05f867c3Sgs 			/*
1854*05f867c3Sgs 			 * A device under a subtractive PPB can allocate
1855*05f867c3Sgs 			 * resources from its parent bus if there is no resource
1856*05f867c3Sgs 			 * available on its own bus.
1857*05f867c3Sgs 			 */
1858*05f867c3Sgs 			if ((config_op == CONFIG_NEW) && (*io_res == NULL)) {
1859*05f867c3Sgs 				res_bus = bus;
1860*05f867c3Sgs 				while (pci_bus_res[res_bus].subtractive) {
1861*05f867c3Sgs 					res_bus = pci_bus_res[res_bus].par_bus;
1862*05f867c3Sgs 					if (res_bus == (uchar_t)-1)
1863*05f867c3Sgs 						break; /* root bus already */
1864*05f867c3Sgs 					if (pci_bus_res[res_bus].io_ports) {
1865*05f867c3Sgs 						io_res = &pci_bus_res
1866*05f867c3Sgs 						    [res_bus].io_ports;
1867*05f867c3Sgs 						break;
1868*05f867c3Sgs 					}
1869*05f867c3Sgs 				}
1870*05f867c3Sgs 			}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 			/*
18737c478bd9Sstevel@tonic-gate 			 * first pass - gather what's there
18747c478bd9Sstevel@tonic-gate 			 * update/second pass - adjust/allocate regions
18757c478bd9Sstevel@tonic-gate 			 *	config - allocate regions
18767c478bd9Sstevel@tonic-gate 			 */
18777c478bd9Sstevel@tonic-gate 			if (config_op == CONFIG_INFO) {	/* first pass */
18787c478bd9Sstevel@tonic-gate 				/* take out of the resource map of the bus */
1879*05f867c3Sgs 				if (base != 0) {
1880*05f867c3Sgs 					if (*io_res)
1881*05f867c3Sgs 						(void) memlist_remove(io_res,
1882*05f867c3Sgs 						    base, len);
1883*05f867c3Sgs 					memlist_insert(io_res_used, base, len);
1884*05f867c3Sgs 				} else
18857c478bd9Sstevel@tonic-gate 					reprogram = 1;
1886*05f867c3Sgs 			} else if ((*io_res && base == 0) ||
1887*05f867c3Sgs 			    pci_bus_res[bus].io_reprogram) {
1888*05f867c3Sgs 				base = (uint_t)memlist_find(io_res, len, 0x4);
18897c478bd9Sstevel@tonic-gate 				if (base != 0) {
1890*05f867c3Sgs 					memlist_insert(io_res_used, base, len);
18917c478bd9Sstevel@tonic-gate 					/* XXX need to worry about 64-bit? */
18927c478bd9Sstevel@tonic-gate 					pci_putl(bus, dev, func, offset,
18937c478bd9Sstevel@tonic-gate 					    base | type);
18947c478bd9Sstevel@tonic-gate 					base = pci_getl(bus, dev, func, offset);
18957c478bd9Sstevel@tonic-gate 					base &= PCI_BASE_IO_ADDR_M;
18967c478bd9Sstevel@tonic-gate 				}
18977c478bd9Sstevel@tonic-gate 				if (base == 0) {
18987c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN, "failed to program"
1899db063408Sdmick 					    " IO space [%d/%d/%d] BAR@0x%x"
1900db063408Sdmick 					    " length 0x%x",
1901ebf3afa8Sdmick 					    bus, dev, func, offset, len);
19027c478bd9Sstevel@tonic-gate 				} else
190346e9e839Smyers 					enable |= PCI_COMM_IO;
19047c478bd9Sstevel@tonic-gate 			}
19057c478bd9Sstevel@tonic-gate 			assigned[nasgn].pci_phys_low = base;
19067c478bd9Sstevel@tonic-gate 			nreg++, nasgn++;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 		} else {
19097c478bd9Sstevel@tonic-gate 			/* memory space */
19107c478bd9Sstevel@tonic-gate 			if ((base & PCI_BASE_TYPE_M) == PCI_BASE_TYPE_ALL) {
19117c478bd9Sstevel@tonic-gate 				bar_sz = PCI_BAR_SZ_64;
19127c478bd9Sstevel@tonic-gate 				base_hi = pci_getl(bus, dev, func, offset + 4);
19137c478bd9Sstevel@tonic-gate 				phys_hi = PCI_ADDR_MEM64;
19147c478bd9Sstevel@tonic-gate 			} else {
19157c478bd9Sstevel@tonic-gate 				bar_sz = PCI_BAR_SZ_32;
19167c478bd9Sstevel@tonic-gate 				base_hi = 0;
19177c478bd9Sstevel@tonic-gate 				phys_hi = PCI_ADDR_MEM32;
19187c478bd9Sstevel@tonic-gate 			}
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 			/* skip base regs with size of 0 */
19217c478bd9Sstevel@tonic-gate 			value &= PCI_BASE_M_ADDR_M;
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 			if (value == 0) {
19247c478bd9Sstevel@tonic-gate 				continue;
19257c478bd9Sstevel@tonic-gate 			}
19267c478bd9Sstevel@tonic-gate 			len = ((value ^ (value-1)) + 1) >> 1;
19277c478bd9Sstevel@tonic-gate 			regs[nreg].pci_size_low =
19287c478bd9Sstevel@tonic-gate 			    assigned[nasgn].pci_size_low = len;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 			phys_hi |= (devloc | offset);
19317c478bd9Sstevel@tonic-gate 			if (base & PCI_BASE_PREF_M) {
19327c478bd9Sstevel@tonic-gate 				mres = pmem_res;
1933*05f867c3Sgs 				mres_used = pmem_res_used;
19347c478bd9Sstevel@tonic-gate 				phys_hi |= PCI_PREFETCH_B;
19357c478bd9Sstevel@tonic-gate 			} else {
19367c478bd9Sstevel@tonic-gate 				mres = mem_res;
1937*05f867c3Sgs 				mres_used = mem_res_used;
19387c478bd9Sstevel@tonic-gate 			}
1939*05f867c3Sgs 			/*
1940*05f867c3Sgs 			 * A device under a subtractive PPB can allocate
1941*05f867c3Sgs 			 * resources from its parent bus if there is no resource
1942*05f867c3Sgs 			 * available on its own bus.
1943*05f867c3Sgs 			 */
1944*05f867c3Sgs 			if ((config_op == CONFIG_NEW) && (*mres == NULL)) {
1945*05f867c3Sgs 				res_bus = bus;
1946*05f867c3Sgs 				while (pci_bus_res[res_bus].subtractive) {
1947*05f867c3Sgs 					res_bus = pci_bus_res[res_bus].par_bus;
1948*05f867c3Sgs 					if (res_bus == (uchar_t)-1)
1949*05f867c3Sgs 						break; /* root bus already */
1950*05f867c3Sgs 					if ((phys_hi & PCI_PREFETCH_B) &&
1951*05f867c3Sgs 					    (res_bus != 0))
1952*05f867c3Sgs 						mres = &pci_bus_res
1953*05f867c3Sgs 						    [res_bus].pmem_space;
1954*05f867c3Sgs 					else
1955*05f867c3Sgs 						mres = &pci_bus_res
1956*05f867c3Sgs 						    [res_bus].mem_space;
1957*05f867c3Sgs 					if (*mres)
1958*05f867c3Sgs 						break;
1959*05f867c3Sgs 				}
1960*05f867c3Sgs 			}
1961*05f867c3Sgs 
19627c478bd9Sstevel@tonic-gate 			regs[nreg].pci_phys_hi =
19637c478bd9Sstevel@tonic-gate 			    assigned[nasgn].pci_phys_hi = phys_hi;
19647c478bd9Sstevel@tonic-gate 			assigned[nasgn].pci_phys_hi |= PCI_RELOCAT_B;
19657c478bd9Sstevel@tonic-gate 			assigned[nasgn].pci_phys_mid = base_hi;
19667c478bd9Sstevel@tonic-gate 			type = base & ~PCI_BASE_M_ADDR_M;
19677c478bd9Sstevel@tonic-gate 			base &= PCI_BASE_M_ADDR_M;
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 			if (config_op == CONFIG_INFO) {
19707c478bd9Sstevel@tonic-gate 				/* take out of the resource map of the bus */
1971*05f867c3Sgs 				if (base != 0) {
1972*05f867c3Sgs 					if (*mres)
1973*05f867c3Sgs 						(void) memlist_remove(mres,
1974*05f867c3Sgs 						    base, len);
1975*05f867c3Sgs 					memlist_insert(mres_used, base, len);
1976*05f867c3Sgs 				} else
19777c478bd9Sstevel@tonic-gate 					reprogram = 1;
1978*05f867c3Sgs 			} else if ((*mres && base == 0) ||
1979*05f867c3Sgs 			    pci_bus_res[bus].mem_reprogram) {
1980*05f867c3Sgs 				base = (uint_t)memlist_find(mres, len, 0x1000);
19817c478bd9Sstevel@tonic-gate 				if (base != NULL) {
1982*05f867c3Sgs 					memlist_insert(mres_used, base, len);
19837c478bd9Sstevel@tonic-gate 					pci_putl(bus, dev, func, offset,
19847c478bd9Sstevel@tonic-gate 					    base | type);
19857c478bd9Sstevel@tonic-gate 					base = pci_getl(bus, dev, func, offset);
19867c478bd9Sstevel@tonic-gate 					base &= PCI_BASE_M_ADDR_M;
19877c478bd9Sstevel@tonic-gate 				}
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate 				if (base == 0) {
19907c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN, "failed to program "
1991ebf3afa8Sdmick 					    "mem space [%d/%d/%d] BAR@0x%x"
1992db063408Sdmick 					    " length 0x%x",
1993ebf3afa8Sdmick 					    bus, dev, func, offset, len);
19947c478bd9Sstevel@tonic-gate 				} else
199546e9e839Smyers 					enable |= PCI_COMM_MAE;
19967c478bd9Sstevel@tonic-gate 			}
19977c478bd9Sstevel@tonic-gate 			assigned[nasgn].pci_phys_low = base;
19987c478bd9Sstevel@tonic-gate 			nreg++, nasgn++;
19997c478bd9Sstevel@tonic-gate 		}
20007c478bd9Sstevel@tonic-gate 	}
20017c478bd9Sstevel@tonic-gate 	switch (header) {
20027c478bd9Sstevel@tonic-gate 	case PCI_HEADER_ZERO:
20037c478bd9Sstevel@tonic-gate 		offset = PCI_CONF_ROM;
20047c478bd9Sstevel@tonic-gate 		break;
20057c478bd9Sstevel@tonic-gate 	case PCI_HEADER_PPB:
20067c478bd9Sstevel@tonic-gate 		offset = PCI_BCNF_ROM;
20077c478bd9Sstevel@tonic-gate 		break;
20087c478bd9Sstevel@tonic-gate 	default: /* including PCI_HEADER_CARDBUS */
20097c478bd9Sstevel@tonic-gate 		goto done;
20107c478bd9Sstevel@tonic-gate 	}
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 	/*
20137c478bd9Sstevel@tonic-gate 	 * Add the expansion rom memory space
20147c478bd9Sstevel@tonic-gate 	 * Determine the size of the ROM base reg; don't write reserved bits
20157c478bd9Sstevel@tonic-gate 	 * ROM isn't in the PCI memory space.
20167c478bd9Sstevel@tonic-gate 	 */
20177c478bd9Sstevel@tonic-gate 	base = pci_getl(bus, dev, func, offset);
20187c478bd9Sstevel@tonic-gate 	pci_putl(bus, dev, func, offset, PCI_BASE_ROM_ADDR_M);
20197c478bd9Sstevel@tonic-gate 	value = pci_getl(bus, dev, func, offset);
20207c478bd9Sstevel@tonic-gate 	pci_putl(bus, dev, func, offset, base);
202170025d76Sjohnny 	if (value & PCI_BASE_ROM_ENABLE)
202270025d76Sjohnny 		value &= PCI_BASE_ROM_ADDR_M;
202370025d76Sjohnny 	else
202470025d76Sjohnny 		value = 0;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	if (value != 0) {
20277c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_hi = (PCI_ADDR_MEM32 | devloc) + offset;
20287c478bd9Sstevel@tonic-gate 		assigned[nasgn].pci_phys_hi = (PCI_RELOCAT_B |
20297c478bd9Sstevel@tonic-gate 		    PCI_ADDR_MEM32 | devloc) + offset;
20307c478bd9Sstevel@tonic-gate 		base &= PCI_BASE_ROM_ADDR_M;
20317c478bd9Sstevel@tonic-gate 		assigned[nasgn].pci_phys_low = base;
20327c478bd9Sstevel@tonic-gate 		len = ((value ^ (value-1)) + 1) >> 1;
20337c478bd9Sstevel@tonic-gate 		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = len;
20347c478bd9Sstevel@tonic-gate 		nreg++, nasgn++;
203599ed6083Sszhou 		/* take it out of the memory resource */
203699ed6083Sszhou 		if (*mem_res && base != 0)
2037*05f867c3Sgs 			(void) memlist_remove(mem_res, base, len);
2038*05f867c3Sgs 		if (base != 0)
2039*05f867c3Sgs 			memlist_insert(mem_res, base, len);
20407c478bd9Sstevel@tonic-gate 	}
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 	/*
20437c478bd9Sstevel@tonic-gate 	 * The following are ISA resources. There are not part
20447c478bd9Sstevel@tonic-gate 	 * of the PCI local bus resources. So don't attempt to
20457c478bd9Sstevel@tonic-gate 	 * do resource accounting against PCI.
20467c478bd9Sstevel@tonic-gate 	 */
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	/* add the three hard-decode, aliased address spaces for VGA */
20497c478bd9Sstevel@tonic-gate 	if ((baseclass == PCI_CLASS_DISPLAY && subclass == PCI_DISPLAY_VGA) ||
20507c478bd9Sstevel@tonic-gate 	    (baseclass == PCI_CLASS_NONE && subclass == PCI_NONE_VGA)) {
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 		/* VGA hard decode 0x3b0-0x3bb */
20537c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
20547c478bd9Sstevel@tonic-gate 		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
20557c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x3b0;
20567c478bd9Sstevel@tonic-gate 		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0xc;
20577c478bd9Sstevel@tonic-gate 		nreg++, nasgn++;
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 		/* VGA hard decode 0x3c0-0x3df */
20607c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
20617c478bd9Sstevel@tonic-gate 		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
20627c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x3c0;
20637c478bd9Sstevel@tonic-gate 		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0x20;
20647c478bd9Sstevel@tonic-gate 		nreg++, nasgn++;
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 		/* Video memory */
20677c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
20687c478bd9Sstevel@tonic-gate 		    (PCI_RELOCAT_B | PCI_ADDR_MEM32 | devloc);
20697c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_low =
20707c478bd9Sstevel@tonic-gate 		    assigned[nasgn].pci_phys_low = 0xa0000;
20717c478bd9Sstevel@tonic-gate 		regs[nreg].pci_size_low =
20727c478bd9Sstevel@tonic-gate 		    assigned[nasgn].pci_size_low = 0x20000;
20737c478bd9Sstevel@tonic-gate 		nreg++, nasgn++;
20747c478bd9Sstevel@tonic-gate 	}
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	/* add the hard-decode, aliased address spaces for 8514 */
20777c478bd9Sstevel@tonic-gate 	if ((baseclass == PCI_CLASS_DISPLAY) &&
20789896aa55Sjveta 	    (subclass == PCI_DISPLAY_VGA) &&
20799896aa55Sjveta 	    (progclass & PCI_DISPLAY_IF_8514)) {
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 		/* hard decode 0x2e8 */
20827c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
20837c478bd9Sstevel@tonic-gate 		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
20847c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x2e8;
20857c478bd9Sstevel@tonic-gate 		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0x1;
20867c478bd9Sstevel@tonic-gate 		nreg++, nasgn++;
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 		/* hard decode 0x2ea-0x2ef */
20897c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
20907c478bd9Sstevel@tonic-gate 		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
20917c478bd9Sstevel@tonic-gate 		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x2ea;
20927c478bd9Sstevel@tonic-gate 		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0x6;
20937c478bd9Sstevel@tonic-gate 		nreg++, nasgn++;
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate done:
20977c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
20987c478bd9Sstevel@tonic-gate 	    (int *)regs, nreg * sizeof (pci_regspec_t) / sizeof (int));
20997c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
21007c478bd9Sstevel@tonic-gate 	    "assigned-addresses",
21017c478bd9Sstevel@tonic-gate 	    (int *)assigned, nasgn * sizeof (pci_regspec_t) / sizeof (int));
2102*05f867c3Sgs 	if ((config_op == CONFIG_NEW) && enable) {
21037c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
2104*05f867c3Sgs 		    "!reprogram PCI device [%x/%x/%x](%s): command = %x.\n",
2105*05f867c3Sgs 		    bus, dev, func, ddi_driver_name(dip), enable);
21068d34f104Smyers 		cmd_reg = pci_getw(bus, dev, func, PCI_CONF_COMM);
210746e9e839Smyers 		cmd_reg |= (enable | PCI_COMM_ME);
21088d34f104Smyers 		pci_putw(bus, dev, func, PCI_CONF_COMM, cmd_reg);
21097c478bd9Sstevel@tonic-gate 	}
21107c478bd9Sstevel@tonic-gate 	return (reprogram);
21117c478bd9Sstevel@tonic-gate }
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate static void
211470025d76Sjohnny add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
211570025d76Sjohnny     int pciex)
21167c478bd9Sstevel@tonic-gate {
211770025d76Sjohnny 	char *dev_type;
21187c478bd9Sstevel@tonic-gate 	int i;
21197c478bd9Sstevel@tonic-gate 	uint_t val, io_range[2], mem_range[2], pmem_range[2];
21207c478bd9Sstevel@tonic-gate 	uchar_t secbus = pci_getb(bus, dev, func, PCI_BCNF_SECBUS);
21217c478bd9Sstevel@tonic-gate 	uchar_t subbus = pci_getb(bus, dev, func, PCI_BCNF_SUBBUS);
2122*05f867c3Sgs 	uchar_t progclass;
2123*05f867c3Sgs 
2124f55ce205Sszhou 	ASSERT(secbus <= subbus);
21257c478bd9Sstevel@tonic-gate 
2126*05f867c3Sgs 	/*
2127*05f867c3Sgs 	 * Check if it's a subtractive PPB.
2128*05f867c3Sgs 	 */
2129*05f867c3Sgs 	progclass = pci_getb(bus, dev, func, PCI_CONF_PROGCLASS);
2130*05f867c3Sgs 	if (progclass == PCI_BRIDGE_PCI_IF_SUBDECODE)
2131*05f867c3Sgs 		pci_bus_res[secbus].subtractive = B_TRUE;
2132*05f867c3Sgs 
2133f55ce205Sszhou 	/*
2134f55ce205Sszhou 	 * Some BIOSes lie about max pci busses, we allow for
2135f55ce205Sszhou 	 * such mistakes here
2136f55ce205Sszhou 	 */
2137f55ce205Sszhou 	if (subbus > pci_bios_nbus) {
2138f55ce205Sszhou 		pci_bios_nbus = subbus;
2139f55ce205Sszhou 		alloc_res_array();
2140f55ce205Sszhou 	}
2141f55ce205Sszhou 
2142f55ce205Sszhou 	ASSERT(pci_bus_res[secbus].dip == NULL);
21437c478bd9Sstevel@tonic-gate 	pci_bus_res[secbus].dip = dip;
21447c478bd9Sstevel@tonic-gate 	pci_bus_res[secbus].par_bus = bus;
21457c478bd9Sstevel@tonic-gate 
214670025d76Sjohnny 	dev_type = pciex ? "pciex" : "pci";
214770025d76Sjohnny 
21487c478bd9Sstevel@tonic-gate 	/* setup bus number hierarchy */
21497c478bd9Sstevel@tonic-gate 	pci_bus_res[secbus].sub_bus = subbus;
215053273e82Ssethg 	/*
215153273e82Ssethg 	 * Keep track of the largest subordinate bus number (this is essential
215253273e82Ssethg 	 * for peer busses because there is no other way of determining its
215353273e82Ssethg 	 * subordinate bus number).
215453273e82Ssethg 	 */
21557c478bd9Sstevel@tonic-gate 	if (subbus > pci_bus_res[bus].sub_bus)
21567c478bd9Sstevel@tonic-gate 		pci_bus_res[bus].sub_bus = subbus;
215753273e82Ssethg 	/*
215853273e82Ssethg 	 * Loop through subordinate busses, initializing their parent bus
215953273e82Ssethg 	 * field to this bridge's parent.  The subordinate busses' parent
216053273e82Ssethg 	 * fields may very well be further refined later, as child bridges
216153273e82Ssethg 	 * are enumerated.  (The value is to note that the subordinate busses
216253273e82Ssethg 	 * are not peer busses by changing their par_bus fields to anything
216353273e82Ssethg 	 * other than -1.)
216453273e82Ssethg 	 */
21657c478bd9Sstevel@tonic-gate 	for (i = secbus + 1; i <= subbus; i++)
21667c478bd9Sstevel@tonic-gate 		pci_bus_res[i].par_bus = bus;
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
216970025d76Sjohnny 	    "device_type", dev_type);
21707c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
21717c478bd9Sstevel@tonic-gate 	    "#address-cells", 3);
21727c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
21737c478bd9Sstevel@tonic-gate 	    "#size-cells", 2);
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	/*
21767c478bd9Sstevel@tonic-gate 	 * According to PPB spec, the base register should be programmed
21777c478bd9Sstevel@tonic-gate 	 * with a value bigger than the limit register when there are
21787c478bd9Sstevel@tonic-gate 	 * no resources available. This applies to io, memory, and
21797c478bd9Sstevel@tonic-gate 	 * prefetchable memory.
21807c478bd9Sstevel@tonic-gate 	 */
21819896aa55Sjveta 
21829896aa55Sjveta 	/*
21839896aa55Sjveta 	 * io range
2184*05f867c3Sgs 	 * We determine i/o windows that are left unconfigured by BIOS
21859896aa55Sjveta 	 * through its i/o enable bit as Microsoft recommends OEMs to do.
21869896aa55Sjveta 	 * If it is unset, we disable i/o and mark it for reconfiguration in
21879896aa55Sjveta 	 * later passes by setting the base > limit
21889896aa55Sjveta 	 */
21899896aa55Sjveta 	val = (uint_t)pci_getw(bus, dev, func, PCI_CONF_COMM);
21909896aa55Sjveta 	if (val & PCI_COMM_IO) {
21919896aa55Sjveta 		val = (uint_t)pci_getb(bus, dev, func, PCI_BCNF_IO_BASE_LOW);
21929896aa55Sjveta 		io_range[0] = ((val & 0xf0) << 8);
21939896aa55Sjveta 		val = (uint_t)pci_getb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW);
21949896aa55Sjveta 		io_range[1]  = ((val & 0xf0) << 8) | 0xFFF;
21959896aa55Sjveta 	} else {
21969896aa55Sjveta 		io_range[0] = 0x9fff;
21979896aa55Sjveta 		io_range[1] = 0x1000;
21989896aa55Sjveta 		pci_putb(bus, dev, func, PCI_BCNF_IO_BASE_LOW,
21999896aa55Sjveta 		    (uint8_t)((io_range[0] >> 8) & 0xf0));
22009896aa55Sjveta 		pci_putb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW,
22019896aa55Sjveta 		    (uint8_t)((io_range[1] >> 8) & 0xf0));
22029896aa55Sjveta 		pci_putw(bus, dev, func, PCI_BCNF_IO_BASE_HI, 0);
22039896aa55Sjveta 		pci_putw(bus, dev, func, PCI_BCNF_IO_LIMIT_HI, 0);
22049896aa55Sjveta 	}
22059896aa55Sjveta 
22067c478bd9Sstevel@tonic-gate 	if (io_range[0] != 0 && io_range[0] < io_range[1]) {
22077c478bd9Sstevel@tonic-gate 		memlist_insert(&pci_bus_res[secbus].io_ports,
22087c478bd9Sstevel@tonic-gate 		    (uint64_t)io_range[0],
22097c478bd9Sstevel@tonic-gate 		    (uint64_t)(io_range[1] - io_range[0] + 1));
2210*05f867c3Sgs 		memlist_insert(&pci_bus_res[bus].io_ports_used,
2211*05f867c3Sgs 		    (uint64_t)io_range[0],
2212*05f867c3Sgs 		    (uint64_t)(io_range[1] - io_range[0] + 1));
22137c478bd9Sstevel@tonic-gate 		if (pci_bus_res[bus].io_ports != NULL) {
22147c478bd9Sstevel@tonic-gate 			(void) memlist_remove(&pci_bus_res[bus].io_ports,
22157c478bd9Sstevel@tonic-gate 			    (uint64_t)io_range[0],
22167c478bd9Sstevel@tonic-gate 			    (uint64_t)(io_range[1] - io_range[0] + 1));
22177c478bd9Sstevel@tonic-gate 		}
22187c478bd9Sstevel@tonic-gate 		dcmn_err(CE_NOTE, "bus %d io-range: 0x%x-%x",
22197c478bd9Sstevel@tonic-gate 		    secbus, io_range[0], io_range[1]);
22202269adc8Sszhou 		/* if 32-bit supported, make sure upper bits are not set */
22212269adc8Sszhou 		if ((val & 0xf) == 1 &&
22222269adc8Sszhou 		    pci_getw(bus, dev, func, PCI_BCNF_IO_BASE_HI)) {
22232269adc8Sszhou 			cmn_err(CE_NOTE, "unsupported 32-bit IO address on"
22242269adc8Sszhou 			    " pci-pci bridge [%d/%d/%d]", bus, dev, func);
22252269adc8Sszhou 		}
22267c478bd9Sstevel@tonic-gate 	}
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 	/* mem range */
22297c478bd9Sstevel@tonic-gate 	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_BASE);
22307c478bd9Sstevel@tonic-gate 	mem_range[0] = ((val & 0xFFF0) << 16);
22317c478bd9Sstevel@tonic-gate 	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_LIMIT);
22327c478bd9Sstevel@tonic-gate 	mem_range[1] = ((val & 0xFFF0) << 16) | 0xFFFFF;
22337c478bd9Sstevel@tonic-gate 	if (mem_range[0] != 0 && mem_range[0] < mem_range[1]) {
22347c478bd9Sstevel@tonic-gate 		memlist_insert(&pci_bus_res[secbus].mem_space,
22357c478bd9Sstevel@tonic-gate 		    (uint64_t)mem_range[0],
22367c478bd9Sstevel@tonic-gate 		    (uint64_t)(mem_range[1] - mem_range[0] + 1));
2237*05f867c3Sgs 		memlist_insert(&pci_bus_res[bus].mem_space_used,
2238*05f867c3Sgs 		    (uint64_t)mem_range[0],
2239*05f867c3Sgs 		    (uint64_t)(mem_range[1] - mem_range[0] + 1));
22407c478bd9Sstevel@tonic-gate 		/* remove from parent resouce list */
22417c478bd9Sstevel@tonic-gate 		if (pci_bus_res[bus].mem_space != NULL) {
22427c478bd9Sstevel@tonic-gate 			(void) memlist_remove(&pci_bus_res[bus].mem_space,
22437c478bd9Sstevel@tonic-gate 			    (uint64_t)mem_range[0],
22447c478bd9Sstevel@tonic-gate 			    (uint64_t)(mem_range[1] - mem_range[0] + 1));
22457c478bd9Sstevel@tonic-gate 		}
22467c478bd9Sstevel@tonic-gate 		dcmn_err(CE_NOTE, "bus %d mem-range: 0x%x-%x",
22477c478bd9Sstevel@tonic-gate 		    secbus, mem_range[0], mem_range[1]);
22487c478bd9Sstevel@tonic-gate 	}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	/* prefetchable memory range */
22517c478bd9Sstevel@tonic-gate 	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_PF_BASE_LOW);
22527c478bd9Sstevel@tonic-gate 	pmem_range[0] = ((val & 0xFFF0) << 16);
22537c478bd9Sstevel@tonic-gate 	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_PF_LIMIT_LOW);
22547c478bd9Sstevel@tonic-gate 	pmem_range[1] = ((val & 0xFFF0) << 16) | 0xFFFFF;
22557c478bd9Sstevel@tonic-gate 	if (pmem_range[0] != 0 && pmem_range[0] < pmem_range[1]) {
22567c478bd9Sstevel@tonic-gate 		memlist_insert(&pci_bus_res[secbus].pmem_space,
22577c478bd9Sstevel@tonic-gate 		    (uint64_t)pmem_range[0],
22587c478bd9Sstevel@tonic-gate 		    (uint64_t)(pmem_range[1] - pmem_range[0] + 1));
2259*05f867c3Sgs 		memlist_insert(&pci_bus_res[bus].pmem_space_used,
2260*05f867c3Sgs 		    (uint64_t)pmem_range[0],
2261*05f867c3Sgs 		    (uint64_t)(pmem_range[1] - pmem_range[0] + 1));
22627c478bd9Sstevel@tonic-gate 		if (pci_bus_res[bus].pmem_space != NULL) {
22637c478bd9Sstevel@tonic-gate 			(void) memlist_remove(&pci_bus_res[bus].pmem_space,
22647c478bd9Sstevel@tonic-gate 			    (uint64_t)pmem_range[0],
22657c478bd9Sstevel@tonic-gate 			    (uint64_t)(pmem_range[1] - pmem_range[0] + 1));
22667c478bd9Sstevel@tonic-gate 		}
22677c478bd9Sstevel@tonic-gate 		dcmn_err(CE_NOTE, "bus %d pmem-range: 0x%x-%x",
22687c478bd9Sstevel@tonic-gate 		    secbus, pmem_range[0], pmem_range[1]);
22692269adc8Sszhou 		/* if 64-bit supported, make sure upper bits are not set */
22702269adc8Sszhou 		if ((val & 0xf) == 1 &&
22712269adc8Sszhou 		    pci_getl(bus, dev, func, PCI_BCNF_PF_BASE_HIGH)) {
22722269adc8Sszhou 			cmn_err(CE_NOTE, "unsupported 64-bit prefetch memory on"
22732269adc8Sszhou 			    " pci-pci bridge [%d/%d/%d]", bus, dev, func);
22742269adc8Sszhou 		}
22757c478bd9Sstevel@tonic-gate 	}
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	add_bus_range_prop(secbus);
22787c478bd9Sstevel@tonic-gate 	add_ppb_ranges_prop(secbus);
22797c478bd9Sstevel@tonic-gate }
22807c478bd9Sstevel@tonic-gate 
228109f67678Sanish extern const struct pci_class_strings_s class_pci[];
228209f67678Sanish extern int class_pci_items;
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate static void
22857c478bd9Sstevel@tonic-gate add_model_prop(dev_info_t *dip, uint_t classcode)
22867c478bd9Sstevel@tonic-gate {
22877c478bd9Sstevel@tonic-gate 	const char *desc;
22887c478bd9Sstevel@tonic-gate 	int i;
22897c478bd9Sstevel@tonic-gate 	uchar_t baseclass = classcode >> 16;
22907c478bd9Sstevel@tonic-gate 	uchar_t subclass = (classcode >> 8) & 0xff;
22917c478bd9Sstevel@tonic-gate 	uchar_t progclass = classcode & 0xff;
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	if ((baseclass == PCI_CLASS_MASS) && (subclass == PCI_MASS_IDE)) {
22947c478bd9Sstevel@tonic-gate 		desc = "IDE controller";
22957c478bd9Sstevel@tonic-gate 	} else {
22967c478bd9Sstevel@tonic-gate 		for (desc = 0, i = 0; i < class_pci_items; i++) {
22977c478bd9Sstevel@tonic-gate 			if ((baseclass == class_pci[i].base_class) &&
22987c478bd9Sstevel@tonic-gate 			    (subclass == class_pci[i].sub_class) &&
22997c478bd9Sstevel@tonic-gate 			    (progclass == class_pci[i].prog_class)) {
230009f67678Sanish 				desc = class_pci[i].actual_desc;
23017c478bd9Sstevel@tonic-gate 				break;
23027c478bd9Sstevel@tonic-gate 			}
23037c478bd9Sstevel@tonic-gate 		}
230409f67678Sanish 		if (i == class_pci_items)
23057c478bd9Sstevel@tonic-gate 			desc = "Unknown class of pci/pnpbios device";
23067c478bd9Sstevel@tonic-gate 	}
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
23097c478bd9Sstevel@tonic-gate 	    (char *)desc);
23107c478bd9Sstevel@tonic-gate }
23117c478bd9Sstevel@tonic-gate 
23127c478bd9Sstevel@tonic-gate static void
23137c478bd9Sstevel@tonic-gate add_bus_range_prop(int bus)
23147c478bd9Sstevel@tonic-gate {
23157c478bd9Sstevel@tonic-gate 	int bus_range[2];
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 	if (pci_bus_res[bus].dip == NULL)
23187c478bd9Sstevel@tonic-gate 		return;
23197c478bd9Sstevel@tonic-gate 	bus_range[0] = bus;
23207c478bd9Sstevel@tonic-gate 	bus_range[1] = pci_bus_res[bus].sub_bus;
23217c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, pci_bus_res[bus].dip,
23227c478bd9Sstevel@tonic-gate 	    "bus-range", (int *)bus_range, 2);
23237c478bd9Sstevel@tonic-gate }
23247c478bd9Sstevel@tonic-gate 
2325b1f176e8Sjg /*
2326b1f176e8Sjg  * Add slot-names property for any named pci hot-plug slots
2327b1f176e8Sjg  */
2328b1f176e8Sjg static void
2329b1f176e8Sjg add_bus_slot_names_prop(int bus)
2330b1f176e8Sjg {
2331b1f176e8Sjg 	char slotprop[256];
2332b1f176e8Sjg 	int len;
2333b1f176e8Sjg 
2334d57b3b3dSprasad 	if (pci_bus_res[bus].dip != NULL) {
2335d57b3b3dSprasad 		/* simply return if the property is already defined */
2336d57b3b3dSprasad 		if (ddi_prop_exists(DDI_DEV_T_ANY, pci_bus_res[bus].dip,
2337d57b3b3dSprasad 		    DDI_PROP_DONTPASS, "slot-names"))
2338d57b3b3dSprasad 			return;
2339d57b3b3dSprasad 	}
2340d57b3b3dSprasad 
2341b1f176e8Sjg 	len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop));
2342b1f176e8Sjg 	if (len > 0) {
234353273e82Ssethg 		/*
234453273e82Ssethg 		 * Only create a peer bus node if this bus may be a peer bus.
234553273e82Ssethg 		 * It may be a peer bus if the dip is NULL and if par_bus is
234653273e82Ssethg 		 * -1 (par_bus is -1 if this bus was not found to be
234753273e82Ssethg 		 * subordinate to any PCI-PCI bridge).
234853273e82Ssethg 		 * If it's not a peer bus, then the ACPI BBN-handling code
234953273e82Ssethg 		 * will remove it later.
235053273e82Ssethg 		 */
235153273e82Ssethg 		if (pci_bus_res[bus].par_bus == (uchar_t)-1 &&
235253273e82Ssethg 		    pci_bus_res[bus].dip == NULL) {
235353273e82Ssethg 
2354b1f176e8Sjg 			create_root_bus_dip(bus);
235553273e82Ssethg 		}
235653273e82Ssethg 		if (pci_bus_res[bus].dip != NULL) {
235753273e82Ssethg 			ASSERT((len % sizeof (int)) == 0);
235853273e82Ssethg 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
235953273e82Ssethg 			    pci_bus_res[bus].dip, "slot-names",
236053273e82Ssethg 			    (int *)slotprop, len / sizeof (int));
236153273e82Ssethg 		} else {
236253273e82Ssethg 			cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI "
236353273e82Ssethg 			    "IRQ routing table; Not adding slot-names "
236453273e82Ssethg 			    "property for incorrect bus %d", bus);
236553273e82Ssethg 		}
2366b1f176e8Sjg 	}
2367b1f176e8Sjg }
2368b1f176e8Sjg 
23697c478bd9Sstevel@tonic-gate static int
237000d0963fSdilpreet memlist_to_range(ppb_ranges_t *rp, struct memlist *entry, int type)
23717c478bd9Sstevel@tonic-gate {
23727c478bd9Sstevel@tonic-gate 	if (entry == NULL)
23737c478bd9Sstevel@tonic-gate 		return (0);
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate 	/* assume 32-bit addresses */
237600d0963fSdilpreet 	rp->child_high = rp->parent_high = type;
23777c478bd9Sstevel@tonic-gate 	rp->child_mid = rp->parent_mid = 0;
237800d0963fSdilpreet 	rp->child_low = rp->parent_low = (uint32_t)entry->address;
237900d0963fSdilpreet 	rp->size_high = 0;
238000d0963fSdilpreet 	rp->size_low = (uint32_t)entry->size;
23817c478bd9Sstevel@tonic-gate 	return (1);
23827c478bd9Sstevel@tonic-gate }
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate static void
23857c478bd9Sstevel@tonic-gate add_ppb_ranges_prop(int bus)
23867c478bd9Sstevel@tonic-gate {
23877c478bd9Sstevel@tonic-gate 	int i = 0;
238800d0963fSdilpreet 	ppb_ranges_t *rp;
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 	rp = kmem_alloc(3 * sizeof (*rp), KM_SLEEP);
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate 	i = memlist_to_range(&rp[0], pci_bus_res[bus].io_ports,
23937c478bd9Sstevel@tonic-gate 	    PCI_ADDR_IO | PCI_REG_REL_M);
23947c478bd9Sstevel@tonic-gate 	i += memlist_to_range(&rp[i], pci_bus_res[bus].mem_space,
23957c478bd9Sstevel@tonic-gate 	    PCI_ADDR_MEM32 | PCI_REG_REL_M);
23967c478bd9Sstevel@tonic-gate 	i += memlist_to_range(&rp[i], pci_bus_res[bus].pmem_space,
23977c478bd9Sstevel@tonic-gate 	    PCI_ADDR_MEM32 | PCI_REG_REL_M | PCI_REG_PF_M);
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	if (i != 0)
24007c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
24017c478bd9Sstevel@tonic-gate 		    pci_bus_res[bus].dip, "ranges", (int *)rp,
240200d0963fSdilpreet 		    i * sizeof (ppb_ranges_t) / sizeof (int));
24037c478bd9Sstevel@tonic-gate 	kmem_free(rp, 3 * sizeof (*rp));
24047c478bd9Sstevel@tonic-gate }
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate static int
24077c478bd9Sstevel@tonic-gate memlist_to_spec(struct pci_phys_spec *sp, struct memlist *list, int type)
24087c478bd9Sstevel@tonic-gate {
24097c478bd9Sstevel@tonic-gate 	int i = 0;
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 	while (list) {
24127c478bd9Sstevel@tonic-gate 		/* assume 32-bit addresses */
24137c478bd9Sstevel@tonic-gate 		sp->pci_phys_hi = type;
24147c478bd9Sstevel@tonic-gate 		sp->pci_phys_mid = 0;
24157c478bd9Sstevel@tonic-gate 		sp->pci_phys_low = (uint32_t)list->address;
24167c478bd9Sstevel@tonic-gate 		sp->pci_size_hi = 0;
24177c478bd9Sstevel@tonic-gate 		sp->pci_size_low = (uint32_t)list->size;
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate 		list = list->next;
24207c478bd9Sstevel@tonic-gate 		sp++, i++;
24217c478bd9Sstevel@tonic-gate 	}
24227c478bd9Sstevel@tonic-gate 	return (i);
24237c478bd9Sstevel@tonic-gate }
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate static void
24267c478bd9Sstevel@tonic-gate add_bus_available_prop(int bus)
24277c478bd9Sstevel@tonic-gate {
24287c478bd9Sstevel@tonic-gate 	int i, count;
24297c478bd9Sstevel@tonic-gate 	struct pci_phys_spec *sp;
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate 	count = memlist_count(pci_bus_res[bus].io_ports) +
24327c478bd9Sstevel@tonic-gate 	    memlist_count(pci_bus_res[bus].mem_space) +
24337c478bd9Sstevel@tonic-gate 	    memlist_count(pci_bus_res[bus].pmem_space);
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate 	if (count == 0)		/* nothing available */
24367c478bd9Sstevel@tonic-gate 		return;
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(count * sizeof (*sp), KM_SLEEP);
24397c478bd9Sstevel@tonic-gate 	i = memlist_to_spec(&sp[0], pci_bus_res[bus].io_ports,
24407c478bd9Sstevel@tonic-gate 	    PCI_ADDR_IO | PCI_REG_REL_M);
24417c478bd9Sstevel@tonic-gate 	i += memlist_to_spec(&sp[i], pci_bus_res[bus].mem_space,
24427c478bd9Sstevel@tonic-gate 	    PCI_ADDR_MEM32 | PCI_REG_REL_M);
24437c478bd9Sstevel@tonic-gate 	i += memlist_to_spec(&sp[i], pci_bus_res[bus].pmem_space,
24447c478bd9Sstevel@tonic-gate 	    PCI_ADDR_MEM32 | PCI_REG_REL_M | PCI_REG_PF_M);
24457c478bd9Sstevel@tonic-gate 	ASSERT(i == count);
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, pci_bus_res[bus].dip,
24487c478bd9Sstevel@tonic-gate 	    "available", (int *)sp,
24497c478bd9Sstevel@tonic-gate 	    i * sizeof (struct pci_phys_spec) / sizeof (int));
24507c478bd9Sstevel@tonic-gate 	kmem_free(sp, count * sizeof (*sp));
24517c478bd9Sstevel@tonic-gate }
2452f55ce205Sszhou 
2453f55ce205Sszhou static void
2454f55ce205Sszhou alloc_res_array(void)
2455f55ce205Sszhou {
2456f55ce205Sszhou 	static int array_max = 0;
2457f55ce205Sszhou 	int old_max;
2458f55ce205Sszhou 	void *old_res;
2459f55ce205Sszhou 
2460f55ce205Sszhou 	if (array_max > pci_bios_nbus + 1)
2461f55ce205Sszhou 		return;	/* array is big enough */
2462f55ce205Sszhou 
2463f55ce205Sszhou 	old_max = array_max;
2464f55ce205Sszhou 	old_res = pci_bus_res;
2465f55ce205Sszhou 
2466f55ce205Sszhou 	if (array_max == 0)
2467f55ce205Sszhou 		array_max = 16;	/* start with a reasonable number */
2468f55ce205Sszhou 
2469f55ce205Sszhou 	while (array_max < pci_bios_nbus + 1)
2470f55ce205Sszhou 		array_max <<= 1;
2471f55ce205Sszhou 	pci_bus_res = (struct pci_bus_resource *)kmem_zalloc(
2472f55ce205Sszhou 	    array_max * sizeof (struct pci_bus_resource), KM_SLEEP);
2473f55ce205Sszhou 
2474f55ce205Sszhou 	if (old_res) {	/* copy content and free old array */
2475f55ce205Sszhou 		bcopy(old_res, pci_bus_res,
2476f55ce205Sszhou 		    old_max * sizeof (struct pci_bus_resource));
2477f55ce205Sszhou 		kmem_free(old_res, old_max * sizeof (struct pci_bus_resource));
2478f55ce205Sszhou 	}
2479f55ce205Sszhou }
2480c8589f13Ssethg 
2481c8589f13Ssethg static void
2482c8589f13Ssethg create_ioapic_node(int bus, int dev, int fn, ushort_t vendorid,
2483c8589f13Ssethg     ushort_t deviceid)
2484c8589f13Ssethg {
2485c8589f13Ssethg 	static dev_info_t *ioapicsnode = NULL;
2486c8589f13Ssethg 	static int numioapics = 0;
2487c8589f13Ssethg 	dev_info_t *ioapic_node;
2488c8589f13Ssethg 	uint64_t physaddr;
2489c8589f13Ssethg 	uint32_t lobase, hibase = 0;
2490c8589f13Ssethg 
2491c8589f13Ssethg 	/* BAR 0 contains the IOAPIC's memory-mapped I/O address */
2492c8589f13Ssethg 	lobase = (*pci_getl_func)(bus, dev, fn, PCI_CONF_BASE0);
2493c8589f13Ssethg 
2494c8589f13Ssethg 	/* We (and the rest of the world) only support memory-mapped IOAPICs */
2495c8589f13Ssethg 	if ((lobase & PCI_BASE_SPACE_M) != PCI_BASE_SPACE_MEM)
2496c8589f13Ssethg 		return;
2497c8589f13Ssethg 
2498c8589f13Ssethg 	if ((lobase & PCI_BASE_TYPE_M) == PCI_BASE_TYPE_ALL)
2499c8589f13Ssethg 		hibase = (*pci_getl_func)(bus, dev, fn, PCI_CONF_BASE0 + 4);
2500c8589f13Ssethg 
2501c8589f13Ssethg 	lobase &= PCI_BASE_M_ADDR_M;
2502c8589f13Ssethg 
2503c8589f13Ssethg 	physaddr = (((uint64_t)hibase) << 32) | lobase;
2504c8589f13Ssethg 
2505c8589f13Ssethg 	/*
2506c8589f13Ssethg 	 * Create a nexus node for all IOAPICs under the root node.
2507c8589f13Ssethg 	 */
2508c8589f13Ssethg 	if (ioapicsnode == NULL) {
2509c8589f13Ssethg 		if (ndi_devi_alloc(ddi_root_node(), IOAPICS_NODE_NAME,
2510c8589f13Ssethg 		    (pnode_t)DEVI_SID_NODEID, &ioapicsnode) != NDI_SUCCESS) {
2511c8589f13Ssethg 			return;
2512c8589f13Ssethg 		}
2513c8589f13Ssethg 		(void) ndi_devi_online(ioapicsnode, 0);
2514c8589f13Ssethg 	}
2515c8589f13Ssethg 
2516c8589f13Ssethg 	/*
2517c8589f13Ssethg 	 * Create a child node for this IOAPIC
2518c8589f13Ssethg 	 */
2519c8589f13Ssethg 	ioapic_node = ddi_add_child(ioapicsnode, IOAPICS_CHILD_NAME,
2520c8589f13Ssethg 	    DEVI_SID_NODEID, numioapics++);
2521c8589f13Ssethg 	if (ioapic_node == NULL) {
2522c8589f13Ssethg 		return;
2523c8589f13Ssethg 	}
2524c8589f13Ssethg 
2525c8589f13Ssethg 	/* Vendor and Device ID */
2526c8589f13Ssethg 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, ioapic_node,
2527c8589f13Ssethg 	    IOAPICS_PROP_VENID, vendorid);
2528c8589f13Ssethg 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, ioapic_node,
2529c8589f13Ssethg 	    IOAPICS_PROP_DEVID, deviceid);
2530c8589f13Ssethg 
2531c8589f13Ssethg 	/* device_type */
2532c8589f13Ssethg 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, ioapic_node,
2533c8589f13Ssethg 	    "device_type", IOAPICS_DEV_TYPE);
2534c8589f13Ssethg 
2535c8589f13Ssethg 	/* reg */
2536c8589f13Ssethg 	(void) ndi_prop_update_int64(DDI_DEV_T_NONE, ioapic_node,
2537c8589f13Ssethg 	    "reg", physaddr);
2538c8589f13Ssethg }
2539d57b3b3dSprasad 
2540d57b3b3dSprasad /*
2541d57b3b3dSprasad  * NOTE: For PCIe slots, the name is generated from the slot number
2542d57b3b3dSprasad  * information obtained from Slot Capabilities register.
2543d57b3b3dSprasad  * For non-PCIe slots, it is generated based on the slot number
2544d57b3b3dSprasad  * information in the PCI IRQ table.
2545d57b3b3dSprasad  */
2546d57b3b3dSprasad static void
2547d57b3b3dSprasad pciex_slot_names_prop(dev_info_t *dip, ushort_t slot_num)
2548d57b3b3dSprasad {
2549d57b3b3dSprasad 	char slotprop[256];
2550d57b3b3dSprasad 	int len;
2551d57b3b3dSprasad 
2552d57b3b3dSprasad 	bzero(slotprop, sizeof (slotprop));
2553d57b3b3dSprasad 
2554d57b3b3dSprasad 	/* set mask to 1 as there is only one slot (i.e dev 0) */
2555d57b3b3dSprasad 	*(uint32_t *)slotprop = 1;
2556d57b3b3dSprasad 	len = 4;
2557d57b3b3dSprasad 	(void) snprintf(slotprop + len, sizeof (slotprop) - len, "pcie%d",
2558d57b3b3dSprasad 	    slot_num);
2559d57b3b3dSprasad 	len += strlen(slotprop + len) + 1;
2560d57b3b3dSprasad 	len += len % 4;
2561d57b3b3dSprasad 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "slot-names",
2562d57b3b3dSprasad 	    (int *)slotprop, len / sizeof (int));
2563d57b3b3dSprasad }
2564