pci_boot.c revision 4876:ecd69ba0713a
1178479Sjb/*
2178479Sjb * CDDL HEADER START
3178479Sjb *
4178479Sjb * The contents of this file are subject to the terms of the
5178479Sjb * Common Development and Distribution License (the "License").
6178479Sjb * You may not use this file except in compliance with the License.
7178479Sjb *
8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178479Sjb * or http://www.opensolaris.org/os/licensing.
10178479Sjb * See the License for the specific language governing permissions
11178479Sjb * and limitations under the License.
12178479Sjb *
13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178479Sjb * If applicable, add the following below this CDDL HEADER, with the
16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178479Sjb *
19178479Sjb * CDDL HEADER END
20178479Sjb */
21178479Sjb/*
22178479Sjb * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23178573Sjb * Use is subject to license terms.
24178479Sjb */
25178479Sjb
26178479Sjb#pragma ident	"%Z%%M%	%I%	%E% SMI"
27178479Sjb
28178479Sjb#include <sys/types.h>
29178479Sjb#include <sys/stat.h>
30178479Sjb#include <sys/sunndi.h>
31178479Sjb#include <sys/pci.h>
32178479Sjb#include <sys/pci_impl.h>
33178573Sjb#include <sys/pci_cfgspace.h>
34178479Sjb#include <sys/memlist.h>
35178573Sjb#include <sys/bootconf.h>
36178573Sjb#include <io/pci/mps_table.h>
37178573Sjb#include <sys/pci_cfgspace.h>
38178479Sjb#include <sys/pci_cfgspace_impl.h>
39178479Sjb#include <sys/psw.h>
40178479Sjb#include "../../../../common/pci/pci_strings.h"
41178573Sjb#include <sys/apic.h>
42178479Sjb#include <io/pciex/pcie_nvidia.h>
43178573Sjb#include <sys/acpi/acpi.h>
44178479Sjb#include <sys/acpica.h>
45178479Sjb
46178479Sjb#define	pci_getb	(*pci_getb_func)
47178479Sjb#define	pci_getw	(*pci_getw_func)
48178479Sjb#define	pci_getl	(*pci_getl_func)
49178479Sjb#define	pci_putb	(*pci_putb_func)
50178573Sjb#define	pci_putw	(*pci_putw_func)
51178479Sjb#define	pci_putl	(*pci_putl_func)
52178573Sjb#define	dcmn_err	if (pci_boot_debug) cmn_err
53178573Sjb
54211554Srpaulo#define	CONFIG_INFO	0
55211554Srpaulo#define	CONFIG_UPDATE	1
56211554Srpaulo#define	CONFIG_NEW	2
57178573Sjb#define	CONFIG_FIX	3
58178479Sjb#define	COMPAT_BUFSIZE	512
59178479Sjb
60178479Sjb/* See AMD-8111 Datasheet Rev 3.03, Page 149: */
61178479Sjb#define	LPC_IO_CONTROL_REG_1	0x40
62178479Sjb#define	AMD8111_ENABLENMI	(uint8_t)0x80
63178479Sjb#define	DEVID_AMD8111_LPC	0x7468
64178479Sjb
65178479Sjbstruct pci_fixundo {
66178479Sjb	uint8_t			bus;
67178479Sjb	uint8_t			dev;
68178479Sjb	uint8_t			fn;
69178479Sjb	void			(*undofn)(uint8_t, uint8_t, uint8_t);
70178479Sjb	struct pci_fixundo	*next;
71178479Sjb};
72178479Sjb
73178479Sjbextern int pci_bios_nbus;
74178479Sjbstatic uchar_t max_dev_pci = 32;	/* PCI standard */
75178479Sjbint pci_boot_debug = 0;
76178479Sjbextern struct memlist *find_bus_res(int, int);
77178479Sjbstatic struct pci_fixundo *undolist = NULL;
78178479Sjb
79178479Sjb/*
80178479Sjb * Module prototypes
81178479Sjb */
82178479Sjbstatic void enumerate_bus_devs(uchar_t bus, int config_op);
83178479Sjbstatic void create_root_bus_dip(uchar_t bus);
84178479Sjbstatic dev_info_t *process_devfunc(uchar_t, uchar_t, uchar_t, uchar_t,
85178479Sjb    ushort_t, int);
86178479Sjbstatic void add_compatible(dev_info_t *, ushort_t, ushort_t,
87178479Sjb    ushort_t, ushort_t, uchar_t, uint_t, int);
88178479Sjbstatic int add_reg_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int, int);
89178479Sjbstatic void add_ppb_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int);
90178479Sjbstatic void add_model_prop(dev_info_t *, uint_t);
91178479Sjbstatic void add_bus_range_prop(int);
92178479Sjbstatic void add_bus_slot_names_prop(int);
93178479Sjbstatic void add_ppb_ranges_prop(int);
94178479Sjbstatic void add_bus_available_prop(int);
95178479Sjbstatic void fix_ppb_res(uchar_t);
96178479Sjbstatic void alloc_res_array();
97178479Sjbstatic void create_ioapic_node(int bus, int dev, int fn, ushort_t vendorid,
98178479Sjb    ushort_t deviceid);
99178479Sjb
100178479Sjbextern int pci_slot_names_prop(int, char *, int);
101178479Sjb
102178479Sjb/* set non-zero to force PCI peer-bus renumbering */
103178479Sjbint pci_bus_always_renumber = 0;
104178479Sjb
105178479Sjb/* get the subordinate bus # for a root/peer bus */
106178479Sjbstatic int
107178479Sjbpci_root_subbus(int bus, uchar_t *subbus)
108178479Sjb{
109178479Sjb	ACPI_HANDLE	hdl;
110178479Sjb	ACPI_BUFFER	rb;
111178479Sjb	ACPI_RESOURCE	*rp;
112178479Sjb	int	rv;
113178479Sjb
114178479Sjb	if (pci_bus_res[bus].dip == NULL) {
115178479Sjb		/* non-used bus # */
116178479Sjb		return (AE_ERROR);
117178479Sjb	}
118178479Sjb	if (acpica_get_handle(pci_bus_res[bus].dip, &hdl) != AE_OK) {
119178479Sjb		cmn_err(CE_WARN, "!No ACPI obj for bus%d, ACPI OFF?\n", bus);
120178479Sjb		return (AE_ERROR);
121178479Sjb	}
122178479Sjb
123178479Sjb	rb.Length = ACPI_ALLOCATE_BUFFER;
124178479Sjb	if (AcpiGetCurrentResources(hdl, &rb) != AE_OK) {
125178479Sjb		cmn_err(CE_WARN, "!_CRS failed on pci%d\n", bus);
126178479Sjb		return (AE_ERROR);
127178479Sjb	}
128178479Sjb
129178479Sjb	rv = AE_ERROR;
130178479Sjb
131178479Sjb	for (rp = rb.Pointer; rp->Type != ACPI_RESOURCE_TYPE_END_TAG;
132178479Sjb	    rp = ACPI_NEXT_RESOURCE(rp)) {
133178479Sjb
134178479Sjb		switch (rp->Type) {
135178479Sjb		case ACPI_RESOURCE_TYPE_ADDRESS16:
136178479Sjb			if (rp->Data.Address.ResourceType !=
137178479Sjb			    ACPI_BUS_NUMBER_RANGE)
138178479Sjb				continue;
139178479Sjb			*subbus = (uchar_t)rp->Data.Address16.Maximum;
140178479Sjb			dcmn_err(CE_NOTE, "Address16,subbus=%d\n", *subbus);
141178479Sjb			break;
142178479Sjb		case ACPI_RESOURCE_TYPE_ADDRESS32:
143178479Sjb			if (rp->Data.Address.ResourceType !=
144178479Sjb			    ACPI_BUS_NUMBER_RANGE)
145178479Sjb				continue;
146178479Sjb			*subbus = (uchar_t)rp->Data.Address32.Maximum;
147178479Sjb			dcmn_err(CE_NOTE, "Address32,subbus=%d\n", *subbus);
148178479Sjb			break;
149178479Sjb		case ACPI_RESOURCE_TYPE_ADDRESS64:
150178479Sjb			if (rp->Data.Address.ResourceType !=
151178479Sjb			    ACPI_BUS_NUMBER_RANGE)
152178479Sjb				continue;
153178479Sjb			*subbus = (uchar_t)rp->Data.Address64.Maximum;
154178479Sjb			dcmn_err(CE_NOTE, "Address64,subbus=%d\n", *subbus);
155178479Sjb			break;
156178479Sjb		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
157178479Sjb			if (rp->Data.Address.ResourceType !=
158178479Sjb			    ACPI_BUS_NUMBER_RANGE)
159178479Sjb				continue;
160178479Sjb			*subbus = (uchar_t)rp->Data.ExtAddress64.Maximum;
161178479Sjb			dcmn_err(CE_NOTE, "ExtAdr64,subbus=%d\n", *subbus);
162178479Sjb			break;
163178479Sjb		default:
164178479Sjb			dcmn_err(CE_NOTE, "rp->Type=%d\n", rp->Type);
165178479Sjb			continue;
166178479Sjb		}
167178479Sjb
168178479Sjb		/* found the bus-range resource */
169178479Sjb		dcmn_err(CE_NOTE, "pci%d, subbus=%d\n", bus, *subbus);
170178479Sjb		rv = AE_OK;
171178479Sjb
172178479Sjb		/* This breaks out of the resource scanning loop */
173178479Sjb		break;
174178479Sjb	}
175178479Sjb
176178479Sjb	AcpiOsFree(rb.Pointer);
177178479Sjb	if (rv != AE_OK)
178178479Sjb		cmn_err(CE_NOTE, "!No bus-range resource for pci%d\n", bus);
179178479Sjb
180178479Sjb	return (rv);
181178479Sjb
182178479Sjb}
183178479Sjb
184178479Sjb/*
185178479Sjb * Enumerate all PCI devices
186178479Sjb */
187178479Sjbvoid
188178479Sjbpci_setup_tree()
189178479Sjb{
190178479Sjb	uchar_t i, root_bus_addr = 0;
191178479Sjb
192178479Sjb	alloc_res_array();
193178479Sjb	for (i = 0; i <= pci_bios_nbus; i++) {
194178479Sjb		pci_bus_res[i].par_bus = (uchar_t)-1;
195178479Sjb		pci_bus_res[i].root_addr = (uchar_t)-1;
196178479Sjb		pci_bus_res[i].sub_bus = i;
197178479Sjb	}
198178479Sjb
199178479Sjb	pci_bus_res[0].root_addr = root_bus_addr++;
200178479Sjb	create_root_bus_dip(0);
201178479Sjb	enumerate_bus_devs(0, CONFIG_INFO);
202178479Sjb
203178479Sjb	/*
204178479Sjb	 * Now enumerate peer busses
205178479Sjb	 *
206178479Sjb	 * We loop till pci_bios_nbus. On most systems, there is
207178479Sjb	 * one more bus at the high end, which implements the ISA
208178479Sjb	 * compatibility bus. We don't care about that.
209178479Sjb	 *
210178479Sjb	 * Note: In the old (bootconf) enumeration, the peer bus
211178479Sjb	 *	address did not use the bus number, and there were
212178479Sjb	 *	too many peer busses created. The root_bus_addr is
213178479Sjb	 *	used to maintain the old peer bus address assignment.
214178479Sjb	 *	However, we stop enumerating phantom peers with no
215178479Sjb	 *	device below.
216178479Sjb	 */
217178479Sjb	for (i = 1; i <= pci_bios_nbus; i++) {
218178479Sjb		if (pci_bus_res[i].dip == NULL) {
219178479Sjb			pci_bus_res[i].root_addr = root_bus_addr++;
220178479Sjb		}
221178479Sjb		enumerate_bus_devs(i, CONFIG_INFO);
222178479Sjb
223178479Sjb		/* add slot-names property for named pci hot-plug slots */
224178479Sjb		add_bus_slot_names_prop(i);
225178479Sjb	}
226178479Sjb
227178479Sjb}
228178479Sjb
229178479Sjb/*
230178573Sjb * >0 = present, 0 = not present, <0 = error
231178573Sjb */
232178573Sjbstatic int
233178573Sjbpci_bbn_present(int bus)
234178573Sjb{
235178573Sjb	ACPI_HANDLE	hdl;
236178573Sjb	ACPI_BUFFER	rb;
237178479Sjb	int	rv;
238178479Sjb
239178479Sjb	/* no dip means no _BBN */
240178479Sjb	if (pci_bus_res[bus].dip == NULL)
241178573Sjb		return (0);
242178573Sjb
243178573Sjb	rv = acpica_get_handle(pci_bus_res[bus].dip, &hdl);
244178573Sjb	if (rv != AE_OK)
245178573Sjb		return (-1);
246178573Sjb
247178479Sjb	rb.Length = ACPI_ALLOCATE_BUFFER;
248178479Sjb
249178479Sjb	rv = AcpiEvaluateObject(hdl, "_BBN", NULL, &rb);
250178479Sjb
251178479Sjb	if (rb.Length > 0)
252178479Sjb		AcpiOsFree(rb.Pointer);
253178479Sjb
254178479Sjb	if (rv == AE_OK)
255178479Sjb		return (1);
256178479Sjb	else if (rv == AE_NOT_FOUND)
257178479Sjb		return (0);
258178479Sjb	else
259178479Sjb		return (-1);
260178479Sjb}
261178479Sjb
262178479Sjb/*
263178479Sjb * Return non-zero if any PCI bus in the system has an associated
264178479Sjb * _BBN object, 0 otherwise.
265178479Sjb */
266178479Sjbstatic int
267178479Sjbpci_roots_have_bbn(void)
268178479Sjb{
269178479Sjb	int	i;
270178479Sjb
271178479Sjb	/*
272178479Sjb	 * Scan the PCI busses and look for at least 1 _BBN
273178479Sjb	 */
274178479Sjb	for (i = 0; i <= pci_bios_nbus; i++) {
275178479Sjb		/* skip non-root (peer) PCI busses */
276178479Sjb		if (pci_bus_res[i].par_bus != (uchar_t)-1)
277178479Sjb			continue;
278178479Sjb
279178479Sjb		if (pci_bbn_present(i) > 0)
280178479Sjb			return (1);
281178479Sjb	}
282178479Sjb	return (0);
283178479Sjb
284178479Sjb}
285178479Sjb
286178479Sjb/*
287178479Sjb * return non-zero if the machine is one on which we renumber
288178479Sjb * the internal pci unit-addresses
289178479Sjb */
290178479Sjbstatic int
291178479Sjbpci_bus_renumber()
292178479Sjb{
293178479Sjb	ACPI_TABLE_HEADER *fadt;
294178479Sjb
295178479Sjb	if (pci_bus_always_renumber)
296178479Sjb		return (1);
297178479Sjb
298178479Sjb	/* get the FADT */
299178479Sjb	if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING,
300178479Sjb	    (ACPI_TABLE_HEADER **)&fadt) != AE_OK)
301178479Sjb		return (0);
302178479Sjb
303178479Sjb	/* compare OEM Table ID to "SUNm31" */
304178479Sjb	if (strncmp("SUNm31", fadt->OemId, 6))
305178479Sjb		return (0);
306178479Sjb	else
307178479Sjb		return (1);
308178479Sjb}
309178479Sjb
310178479Sjb/*
311178479Sjb * Initial enumeration of the physical PCI bus hierarchy can
312178479Sjb * leave 'gaps' in the order of peer PCI bus unit-addresses.
313178479Sjb * Systems with more than one peer PCI bus *must* have an ACPI
314178479Sjb * _BBN object associated with each peer bus; use the presence
315178479Sjb * of this object to remove gaps in the numbering of the peer
316178479Sjb * PCI bus unit-addresses - only peer busses with an associated
317178479Sjb * _BBN are counted.
318178479Sjb */
319178479Sjbstatic void
320178479Sjbpci_renumber_root_busses(void)
321178479Sjb{
322178479Sjb	int pci_regs[] = {0, 0, 0};
323178479Sjb	int	i, root_addr = 0;
324178479Sjb
325178479Sjb	/*
326178479Sjb	 * Currently, we only enable the re-numbering on specific
327178479Sjb	 * Sun machines; this is a work-around for the more complicated
328178479Sjb	 * issue of upgrade changing physical device paths
329178479Sjb	 */
330178479Sjb	if (!pci_bus_renumber())
331178479Sjb		return;
332178479Sjb
333178479Sjb	/*
334178479Sjb	 * If we find no _BBN objects at all, we either don't need
335178479Sjb	 * to do anything or can't do anything anyway
336178479Sjb	 */
337178479Sjb	if (!pci_roots_have_bbn())
338178479Sjb		return;
339178479Sjb
340178479Sjb	for (i = 0; i <= pci_bios_nbus; i++) {
341178479Sjb		/* skip non-root (peer) PCI busses */
342178479Sjb		if (pci_bus_res[i].par_bus != (uchar_t)-1)
343178479Sjb			continue;
344178479Sjb
345178479Sjb		if (pci_bbn_present(i) < 1) {
346178479Sjb			pci_bus_res[i].root_addr = (uchar_t)-1;
347178479Sjb			continue;
348178479Sjb		}
349178479Sjb
350178479Sjb		ASSERT(pci_bus_res[i].dip != NULL);
351178479Sjb		if (pci_bus_res[i].root_addr != root_addr) {
352178479Sjb			/* update reg property for node */
353178479Sjb			pci_bus_res[i].root_addr = root_addr;
354178479Sjb			pci_regs[0] = pci_bus_res[i].root_addr;
355178479Sjb			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
356178479Sjb			    pci_bus_res[i].dip, "reg", (int *)pci_regs, 3);
357178479Sjb		}
358178479Sjb		root_addr++;
359178479Sjb	}
360178479Sjb}
361178479Sjb
362178479Sjbstatic void
363178479Sjbremove_resource_range(struct memlist **list, int *ranges, int range_count)
364178479Sjb{
365178479Sjb	struct range {
366178479Sjb		uint32_t base;
367178479Sjb		uint32_t len;
368178479Sjb	};
369178479Sjb	int index;
370178479Sjb
371178479Sjb	for (index = 0; index < range_count; index++) {
372178479Sjb		/* all done if list is or has become empty */
373178479Sjb		if (*list == NULL)
374178479Sjb			break;
375178479Sjb		(void) memlist_remove(list,
376178479Sjb		    (uint64_t)((struct range *)ranges)[index].base,
377178479Sjb		    (uint64_t)((struct range *)ranges)[index].len);
378178479Sjb	}
379178479Sjb}
380178479Sjb
381178479Sjbstatic void
382178479Sjbremove_used_resources()
383178479Sjb{
384178479Sjb	dev_info_t *used;
385178479Sjb	int	*narray;
386178479Sjb	uint_t	ncount;
387178479Sjb	int	status;
388178479Sjb	int	bus;
389178479Sjb
390178479Sjb	used = ddi_find_devinfo("used-resources", -1, 0);
391178479Sjb	if (used == NULL)
392178479Sjb		return;
393178479Sjb
394178479Sjb	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
395178479Sjb	    DDI_PROP_DONTPASS, "io-space", &narray, &ncount);
396178479Sjb	if (status == DDI_PROP_SUCCESS) {
397178479Sjb		for (bus = 0; bus <= pci_bios_nbus; bus++)
398178479Sjb			remove_resource_range(&pci_bus_res[bus].io_ports,
399178479Sjb			    narray, ncount / 2);
400178479Sjb		ddi_prop_free(narray);
401178479Sjb	}
402178479Sjb
403178479Sjb	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
404178479Sjb	    DDI_PROP_DONTPASS, "device-memory", &narray, &ncount);
405178479Sjb	if (status == DDI_PROP_SUCCESS) {
406178479Sjb		for (bus = 0; bus <= pci_bios_nbus; bus++)
407178479Sjb			remove_resource_range(&pci_bus_res[bus].mem_space,
408178479Sjb			    narray, ncount / 2);
409178479Sjb		ddi_prop_free(narray);
410178479Sjb	}
411178479Sjb}
412178479Sjb
413178479Sjb/*
414178479Sjb * Assign i/o resources to unconfigured hotplug bridges after the first pass.
415178479Sjb * It must be after the first pass in order to use the ports left over after
416178479Sjb * accounting for i/o resources of bridges that have been configured by bios.
417178479Sjb * We are expecting unconfigured bridges to be empty bridges otherwise
418178573Sjb * this resource assignment needs to be done at an earlier stage.
419178573Sjb */
420178573Sjbstatic void
421178573Sjbfix_ppb_res(uchar_t secbus)
422178573Sjb{
423178573Sjb	uchar_t bus, dev, func;
424178573Sjb	uint_t io_base, io_limit, io_size = 0x1000;
425178573Sjb	uint64_t addr = 0;
426178573Sjb	int *regp = NULL, rv;
427178573Sjb	uint_t reglen;
428178479Sjb	dev_info_t *dip;
429178479Sjb
430178479Sjb	dip = pci_bus_res[secbus].dip;
431178479Sjb	/* some entries may be empty due to discontiguous bus numbering */
432178479Sjb	if (dip == NULL)
433178479Sjb		return;
434178479Sjb
435178479Sjb	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
436178479Sjb	    "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
437178479Sjb		return;
438178479Sjb
439178479Sjb	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
440178573Sjb	    "reg", &regp, &reglen);
441178479Sjb	if (rv != DDI_PROP_SUCCESS || reglen == 0) {
442178479Sjb		/* panic to enforce proper calling order */
443178479Sjb		cmn_err(CE_PANIC, "reg property unset for bus %d\n", secbus);
444178479Sjb		return;
445178479Sjb	}
446178479Sjb
447178479Sjb	func = (uchar_t)((regp[0] >> 8) & 0x7);
448178479Sjb	dev = (uchar_t)((regp[0] >> 11) & 0x1f);
449178479Sjb	bus = (uchar_t)((regp[0] >> 16) & 0xff);
450178479Sjb	ASSERT(bus == pci_bus_res[secbus].par_bus);
451178479Sjb
452178479Sjb	/*
453178479Sjb	 * io_base >= io_limit means that the bridge was not configured
454178479Sjb	 * This may have been set by the bios or by add_ppb_props()
455178479Sjb	 */
456178479Sjb	io_base = pci_getb(bus, dev, func, PCI_BCNF_IO_BASE_LOW);
457178479Sjb	io_limit = pci_getb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW);
458178479Sjb	ASSERT(io_base != 0xff && io_limit != 0xff);
459178479Sjb
460178479Sjb	io_base = (io_base & 0xf0) << 8;
461178479Sjb	io_limit = ((io_limit & 0xf0) << 8) | 0xfff;
462178479Sjb	if (io_base < io_limit && io_base != 0)
463178479Sjb		return;
464178479Sjb
465178479Sjb	if (ddi_get_child(dip) != NULL) {
466178479Sjb		cmn_err(CE_WARN, "detected unsupported configuration: "
467178479Sjb		    "non-empty bridge (bus 0x%x, dev 0x%x, func 0x%x) without "
468178479Sjb		    "I/O resources assigned by bios for secondary bus 0x%x\n",
469178479Sjb		    bus, dev, func, secbus);
470178479Sjb		goto IOFAIL;
471178479Sjb	}
472178479Sjb
473178479Sjb	if (pci_bus_res[bus].io_ports != NULL)
474178479Sjb		addr = memlist_find(&pci_bus_res[bus].io_ports, io_size,
475178479Sjb		    0x1000);
476178479Sjb
477178479Sjb	ASSERT(addr <= 0xf000);
478178479Sjb	if (addr == 0) {
479178479Sjb		cmn_err(CE_WARN, "out of I/O resources on bridge: bus 0x%x, "
480178479Sjb		    "dev 0x%x, func 0x%x, for secondary bus 0x%x\n",
481178479Sjb		    bus, dev, func, secbus);
482178479Sjb		goto IOFAIL;
483178479Sjb	}
484178479Sjb
485178479Sjb	memlist_insert(&pci_bus_res[secbus].io_ports, addr, io_size);
486178479Sjb	io_base = addr;
487178479Sjb	io_limit = addr + io_size - 1;
488178479Sjb	pci_putb(bus, dev, func, PCI_BCNF_IO_BASE_LOW,
489178479Sjb	    (uint8_t)((io_base >> 8) & 0xf0));
490178479Sjb	pci_putb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW,
491178479Sjb	    (uint8_t)((io_limit >> 8) & 0xf0));
492178479Sjb
493178479Sjb	add_ppb_ranges_prop(secbus);
494178479Sjb	return;
495178479Sjb
496178479Sjb	/*NOTREACHED*/
497178479SjbIOFAIL:
498178479Sjb	cmn_err(CE_WARN, "devices under bridge bus 0x%x, dev 0x%x, func 0x%x "
499178479Sjb	    "will not be assigned I/O ports\n", bus, dev, func);
500178479Sjb}
501178479Sjb
502178479Sjbvoid
503178479Sjbpci_reprogram(void)
504178479Sjb{
505178479Sjb	int i, pci_reconfig = 1;
506178479Sjb	char *onoff;
507178479Sjb
508178479Sjb	/*
509178479Sjb	 * Excise phantom roots if possible
510178479Sjb	 */
511178479Sjb	pci_renumber_root_busses();
512178479Sjb
513178479Sjb	/* add bus-range property for root/peer bus nodes */
514178479Sjb	for (i = 0; i <= pci_bios_nbus; i++) {
515178479Sjb		if (pci_bus_res[i].par_bus == (uchar_t)-1) {
516178479Sjb			uchar_t subbus;
517178479Sjb			if (pci_root_subbus(i, &subbus) == AE_OK)
518178573Sjb				pci_bus_res[i].sub_bus = subbus;
519178479Sjb			add_bus_range_prop(i);
520178573Sjb		}
521178479Sjb	}
522178479Sjb
523178573Sjb	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
524178573Sjb	    DDI_PROP_DONTPASS, "pci-reprog", &onoff) == DDI_SUCCESS) {
525178573Sjb		if (strcmp(onoff, "off") == 0) {
526178479Sjb			pci_reconfig = 0;
527178573Sjb			cmn_err(CE_NOTE, "pci device reprogramming disabled");
528178573Sjb		}
529178573Sjb		ddi_prop_free(onoff);
530178573Sjb	}
531178573Sjb
532178573Sjb	/* remove used-resources from PCI resource maps */
533178573Sjb	remove_used_resources();
534178573Sjb
535178573Sjb	for (i = 0; i <= pci_bios_nbus; i++) {
536178479Sjb		/* configure devices not configured by bios */
537178479Sjb		if (pci_reconfig) {
538178479Sjb			fix_ppb_res(i);
539178479Sjb			enumerate_bus_devs(i, CONFIG_NEW);
540178479Sjb		}
541178479Sjb		/* All dev programmed, so we can create available prop */
542178479Sjb		add_bus_available_prop(i);
543178479Sjb	}
544178479Sjb}
545178479Sjb
546178479Sjb/*
547178479Sjb * Create top-level bus dips, i.e. /pci@0,0, /pci@1,0...
548178479Sjb */
549178479Sjbstatic void
550178479Sjbcreate_root_bus_dip(uchar_t bus)
551178479Sjb{
552178479Sjb	int pci_regs[] = {0, 0, 0};
553178479Sjb	dev_info_t *dip;
554178479Sjb
555178479Sjb	ASSERT(pci_bus_res[bus].par_bus == (uchar_t)-1);
556178479Sjb
557178479Sjb	ndi_devi_alloc_sleep(ddi_root_node(), "pci",
558178479Sjb	    (pnode_t)DEVI_SID_NODEID, &dip);
559178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
560178479Sjb	    "#address-cells", 3);
561178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
562178479Sjb	    "#size-cells", 2);
563178479Sjb	pci_regs[0] = pci_bus_res[bus].root_addr;
564178479Sjb	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
565178479Sjb	    "reg", (int *)pci_regs, 3);
566178479Sjb
567178479Sjb	/*
568178479Sjb	 * If system has PCIe bus, then create different properties
569178479Sjb	 */
570178479Sjb	if (create_pcie_root_bus(bus, dip) == B_FALSE)
571178479Sjb		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
572178479Sjb		    "device_type", "pci");
573178479Sjb
574178479Sjb	(void) ndi_devi_bind_driver(dip, 0);
575178479Sjb	pci_bus_res[bus].dip = dip;
576178479Sjb	pci_bus_res[bus].pmem_space = find_bus_res(bus, PREFETCH_TYPE);
577178479Sjb	pci_bus_res[bus].mem_space = find_bus_res(bus, MEM_TYPE);
578178479Sjb	pci_bus_res[bus].io_ports = find_bus_res(bus, IO_TYPE);
579178479Sjb
580178479Sjb	if (bus != 0)
581178479Sjb		return;
582178479Sjb
583178479Sjb	/*
584178479Sjb	 * Special treatment of bus 0:
585178479Sjb	 * If no resource from MPSPEC/HRT, copy pcimem from boot
586178479Sjb	 * and make I/O space the entire range starting at 0x100. There
587178479Sjb	 * is no difference between prefetchable memory or not.
588178479Sjb	 */
589178479Sjb	if (pci_bus_res[0].mem_space == NULL)
590178479Sjb		pci_bus_res[0].mem_space =
591178479Sjb		    memlist_dup(bootops->boot_mem->pcimem);
592178479Sjb	/* Exclude 0x00 to 0xff of the I/O space, used by all PCs */
593178479Sjb	if (pci_bus_res[0].io_ports == NULL)
594178479Sjb		memlist_insert(&pci_bus_res[0].io_ports, 0x100, 0xff00);
595178479Sjb}
596178479Sjb
597178479Sjb/*
598178479Sjb * For any fixed configuration (often compatability) pci devices
599178479Sjb * and those with their own expansion rom, create device nodes
600178479Sjb * to hold the already configured device details.
601178479Sjb */
602178479Sjbvoid
603178479Sjbenumerate_bus_devs(uchar_t bus, int config_op)
604178479Sjb{
605178479Sjb	uchar_t dev, func, nfunc, header;
606178479Sjb	ushort_t venid;
607178479Sjb	dev_info_t *dip;
608178479Sjb	struct pci_devfunc {
609178479Sjb		struct pci_devfunc *next;
610178479Sjb		dev_info_t *dip;
611178479Sjb		uchar_t bus;
612178479Sjb		uchar_t dev;
613178479Sjb		uchar_t func;
614178479Sjb	} *devlist = NULL, *entry;
615178479Sjb
616178479Sjb	if (config_op == CONFIG_NEW) {
617178479Sjb		dcmn_err(CE_NOTE, "configuring pci bus 0x%x", bus);
618178479Sjb	} else if (config_op == CONFIG_FIX) {
619178479Sjb		dcmn_err(CE_NOTE, "fixing devices on pci bus 0x%x", bus);
620178479Sjb	} else
621178479Sjb		dcmn_err(CE_NOTE, "enumerating pci bus 0x%x", bus);
622178479Sjb
623178479Sjb	for (dev = 0; dev < max_dev_pci; dev++) {
624178479Sjb		nfunc = 1;
625178479Sjb		for (func = 0; func < nfunc; func++) {
626178479Sjb
627178479Sjb			dcmn_err(CE_NOTE, "probing dev 0x%x, func 0x%x",
628178479Sjb			    dev, func);
629178479Sjb
630178479Sjb			venid = pci_getw(bus, dev, func, PCI_CONF_VENID);
631178479Sjb
632178479Sjb			if ((venid == 0xffff) || (venid == 0)) {
633178479Sjb				/* no function at this address */
634178479Sjb				continue;
635178479Sjb			}
636178479Sjb
637178479Sjb			header = pci_getb(bus, dev, func, PCI_CONF_HEADER);
638178479Sjb			if (header == 0xff) {
639178479Sjb				continue; /* illegal value */
640178479Sjb			}
641178479Sjb
642178479Sjb			/*
643178479Sjb			 * according to some mail from Microsoft posted
644178479Sjb			 * to the pci-drivers alias, their only requirement
645178479Sjb			 * for a multifunction device is for the 1st
646178479Sjb			 * function to have to PCI_HEADER_MULTI bit set.
647178479Sjb			 */
648178479Sjb			if ((func == 0) && (header & PCI_HEADER_MULTI)) {
649178479Sjb				nfunc = 8;
650178479Sjb			}
651178479Sjb
652178479Sjb			if (config_op == CONFIG_FIX) {
653178479Sjb				/*
654178479Sjb				 * If we're processing PCI fixes, no dip
655178479Sjb				 * will be returned.
656178479Sjb				 */
657178479Sjb				(void) process_devfunc(bus, dev, func, header,
658178479Sjb				    venid, config_op);
659178479Sjb
660178479Sjb			} else if (config_op == CONFIG_INFO) {
661178479Sjb				/*
662178479Sjb				 * Create the node, unconditionally, on the
663178479Sjb				 * first pass only.  It may still need
664178479Sjb				 * resource assignment, which will be
665178479Sjb				 * done on the second, CONFIG_NEW, pass.
666178573Sjb				 */
667178479Sjb				dip = process_devfunc(bus, dev, func, header,
668178573Sjb				    venid, config_op);
669178479Sjb				/*
670178479Sjb				 * If dip isn't null, put on a list to
671178573Sjb				 * save for reprogramming when config_op
672178573Sjb				 * is CONFIG_NEW.
673178573Sjb				 */
674178479Sjb
675178573Sjb				if (dip) {
676178573Sjb					entry = kmem_alloc(sizeof (*entry),
677178573Sjb					    KM_SLEEP);
678178573Sjb					entry->dip = dip;
679178573Sjb					entry->dev = dev;
680178573Sjb					entry->func = func;
681178573Sjb					entry->next = devlist;
682178573Sjb					devlist = entry;
683178573Sjb				}
684178479Sjb			}
685178479Sjb		}
686178479Sjb	}
687178479Sjb
688178479Sjb	if (config_op == CONFIG_NEW) {
689178479Sjb		devlist = (struct pci_devfunc *)pci_bus_res[bus].privdata;
690178479Sjb		while (devlist) {
691178479Sjb			entry = devlist;
692178479Sjb			devlist = entry->next;
693178479Sjb			cmn_err(CE_NOTE,
694178479Sjb			    "!reprogram pci device [%d/%d/%d] (%s)",
695178479Sjb			    bus, entry->dev, entry->func,
696178479Sjb			    ddi_driver_name(entry->dip));
697178479Sjb			(void) add_reg_props(entry->dip, bus, entry->dev,
698178479Sjb			    entry->func, CONFIG_UPDATE, 0);
699178479Sjb			kmem_free(entry, sizeof (*entry));
700178479Sjb		}
701178479Sjb		pci_bus_res[bus].privdata = NULL;
702178479Sjb	} else if (config_op != CONFIG_FIX) {
703178479Sjb		pci_bus_res[bus].privdata = devlist;
704178479Sjb	}
705178479Sjb}
706178479Sjb
707178479Sjbstatic int
708178479Sjbcheck_pciide_prop(uchar_t revid, ushort_t venid, ushort_t devid,
709178479Sjb    ushort_t subvenid, ushort_t subdevid)
710178479Sjb{
711178479Sjb	static int prop_exist = -1;
712178479Sjb	static char *pciide_str;
713178479Sjb	char compat[32];
714178479Sjb
715178479Sjb	if (prop_exist == -1) {
716178479Sjb		prop_exist = (ddi_prop_lookup_string(DDI_DEV_T_ANY,
717178479Sjb		    ddi_root_node(), DDI_PROP_DONTPASS, "pci-ide",
718178479Sjb		    &pciide_str) == DDI_SUCCESS);
719178479Sjb	}
720178479Sjb
721178479Sjb	if (!prop_exist)
722178479Sjb		return (0);
723178479Sjb
724178479Sjb	/* compare property value against various forms of compatible */
725178479Sjb	if (subvenid) {
726178479Sjb		(void) snprintf(compat, sizeof (compat), "pci%x,%x.%x.%x.%x",
727178479Sjb		    venid, devid, subvenid, subdevid, revid);
728178479Sjb		if (strcmp(pciide_str, compat) == 0)
729178479Sjb			return (1);
730178479Sjb
731178479Sjb		(void) snprintf(compat, sizeof (compat), "pci%x,%x.%x.%x",
732178479Sjb		    venid, devid, subvenid, subdevid);
733178479Sjb		if (strcmp(pciide_str, compat) == 0)
734178479Sjb			return (1);
735178479Sjb
736178479Sjb		(void) snprintf(compat, sizeof (compat), "pci%x,%x",
737178479Sjb		    subvenid, subdevid);
738178479Sjb		if (strcmp(pciide_str, compat) == 0)
739178479Sjb			return (1);
740178479Sjb	}
741178479Sjb	(void) snprintf(compat, sizeof (compat), "pci%x,%x.%x",
742178479Sjb	    venid, devid, revid);
743178479Sjb	if (strcmp(pciide_str, compat) == 0)
744178479Sjb		return (1);
745178479Sjb
746178479Sjb	(void) snprintf(compat, sizeof (compat), "pci%x,%x", venid, devid);
747178479Sjb	if (strcmp(pciide_str, compat) == 0)
748178479Sjb		return (1);
749178479Sjb
750178479Sjb	return (0);
751178479Sjb}
752178479Sjb
753178479Sjbstatic int
754178479Sjbis_pciide(uchar_t basecl, uchar_t subcl, uchar_t revid,
755178479Sjb    ushort_t venid, ushort_t devid, ushort_t subvenid, ushort_t subdevid)
756178479Sjb{
757178479Sjb	struct ide_table {	/* table for PCI_MASS_OTHER */
758178479Sjb		ushort_t venid;
759178479Sjb		ushort_t devid;
760178479Sjb	} *entry;
761178479Sjb
762178479Sjb	/* XXX SATA devices: need a way to add dynamically */
763178479Sjb	static struct ide_table ide_other[] = {
764178479Sjb		{0x1095, 0x3112},
765178479Sjb		{0x1095, 0x3114},
766178479Sjb		{0x1095, 0x3512},
767178479Sjb		{0, 0}
768178479Sjb	};
769178479Sjb
770178479Sjb	if (basecl != PCI_CLASS_MASS)
771178479Sjb		return (0);
772178479Sjb
773178479Sjb	if (subcl == PCI_MASS_IDE) {
774178479Sjb		return (1);
775178479Sjb	}
776178479Sjb
777178479Sjb	if (subcl != PCI_MASS_OTHER && subcl != PCI_MASS_SATA) {
778178479Sjb		return (0);
779178479Sjb	}
780178479Sjb
781178479Sjb	entry = &ide_other[0];
782178479Sjb	while (entry->venid) {
783178479Sjb		if (entry->venid == venid && entry->devid == devid)
784178479Sjb			return (1);
785178479Sjb		entry++;
786178479Sjb	}
787178479Sjb	return (check_pciide_prop(revid, venid, devid, subvenid, subdevid));
788178479Sjb}
789178479Sjb
790178479Sjbstatic int
791178479Sjbis_display(uint_t classcode)
792178479Sjb{
793178479Sjb	static uint_t disp_classes[] = {
794178479Sjb		0x000100,
795178479Sjb		0x030000,
796178479Sjb		0x030001
797178479Sjb	};
798178479Sjb	int i, nclasses = sizeof (disp_classes) / sizeof (uint_t);
799178573Sjb
800178573Sjb	for (i = 0; i < nclasses; i++) {
801178573Sjb		if (classcode == disp_classes[i])
802178573Sjb			return (1);
803178573Sjb	}
804178573Sjb	return (0);
805178573Sjb}
806178573Sjb
807178573Sjbstatic void
808178573Sjbadd_undofix_entry(uint8_t bus, uint8_t dev, uint8_t fn,
809178573Sjb    void (*undofn)(uint8_t, uint8_t, uint8_t))
810178573Sjb{
811178573Sjb	struct pci_fixundo *newundo;
812178573Sjb
813178573Sjb	newundo = kmem_alloc(sizeof (struct pci_fixundo), KM_SLEEP);
814178573Sjb
815178573Sjb	/*
816178573Sjb	 * Adding an item to this list means that we must turn its NMIENABLE
817178573Sjb	 * bit back on at a later time.
818178573Sjb	 */
819178573Sjb	newundo->bus = bus;
820178573Sjb	newundo->dev = dev;
821178573Sjb	newundo->fn = fn;
822178573Sjb	newundo->undofn = undofn;
823178573Sjb	newundo->next = undolist;
824178573Sjb
825178573Sjb	/* add to the undo list in LIFO order */
826178573Sjb	undolist = newundo;
827178573Sjb}
828178573Sjb
829178573Sjbvoid
830178573Sjbadd_pci_fixes(void)
831178573Sjb{
832178573Sjb	int i;
833178573Sjb
834178573Sjb	for (i = 0; i <= pci_bios_nbus; i++) {
835178479Sjb		/*
836178573Sjb		 * For each bus, apply needed fixes to the appropriate devices.
837178573Sjb		 * This must be done before the main enumeration loop because
838178479Sjb		 * some fixes must be applied to devices normally encountered
839178479Sjb		 * later in the pci scan (e.g. if a fix to device 7 must be
840178479Sjb		 * applied before scanning device 6, applying fixes in the
841178479Sjb		 * normal enumeration loop would obviously be too late).
842178479Sjb		 */
843178479Sjb		enumerate_bus_devs(i, CONFIG_FIX);
844178479Sjb	}
845178479Sjb}
846178479Sjb
847178479Sjbvoid
848178479Sjbundo_pci_fixes(void)
849178479Sjb{
850178479Sjb	struct pci_fixundo *nextundo;
851178479Sjb	uint8_t bus, dev, fn;
852178479Sjb
853178479Sjb	/*
854178479Sjb	 * All fixes in the undo list are performed unconditionally.  Future
855178479Sjb	 * fixes may require selective undo.
856178479Sjb	 */
857178479Sjb	while (undolist != NULL) {
858178479Sjb
859178479Sjb		bus = undolist->bus;
860178479Sjb		dev = undolist->dev;
861178479Sjb		fn = undolist->fn;
862178479Sjb
863178479Sjb		(*(undolist->undofn))(bus, dev, fn);
864178479Sjb
865178479Sjb		nextundo = undolist->next;
866178479Sjb		kmem_free(undolist, sizeof (struct pci_fixundo));
867178479Sjb		undolist = nextundo;
868178479Sjb	}
869178479Sjb}
870178479Sjb
871178479Sjbstatic void
872178479Sjbundo_amd8111_pci_fix(uint8_t bus, uint8_t dev, uint8_t fn)
873184696Srodrigc{
874178479Sjb	uint8_t val8;
875178479Sjb
876184696Srodrigc	val8 = pci_getb(bus, dev, fn, LPC_IO_CONTROL_REG_1);
877184696Srodrigc	/*
878178479Sjb	 * The NMIONERR bit is turned back on to allow the SMM BIOS
879184696Srodrigc	 * to handle more critical PCI errors (e.g. PERR#).
880178479Sjb	 */
881178479Sjb	val8 |= AMD8111_ENABLENMI;
882184696Srodrigc	pci_putb(bus, dev, fn, LPC_IO_CONTROL_REG_1, val8);
883184696Srodrigc}
884178479Sjb
885184696Srodrigcstatic void
886178479Sjbpci_fix_amd8111(uint8_t bus, uint8_t dev, uint8_t fn)
887178479Sjb{
888178479Sjb	uint8_t val8;
889178479Sjb
890178479Sjb	val8 = pci_getb(bus, dev, fn, LPC_IO_CONTROL_REG_1);
891178479Sjb
892178479Sjb	if ((val8 & AMD8111_ENABLENMI) == 0)
893178479Sjb		return;
894178479Sjb
895178479Sjb	/*
896178479Sjb	 * We reset NMIONERR in the LPC because master-abort on the PCI
897178479Sjb	 * bridge side of the 8111 will cause NMI, which might cause SMI,
898178479Sjb	 * which sometimes prevents all devices from being enumerated.
899178479Sjb	 */
900178479Sjb	val8 &= ~AMD8111_ENABLENMI;
901178479Sjb
902178479Sjb	pci_putb(bus, dev, fn, LPC_IO_CONTROL_REG_1, val8);
903178479Sjb
904178479Sjb	add_undofix_entry(bus, dev, fn, undo_amd8111_pci_fix);
905178479Sjb}
906178479Sjb
907178479Sjbstatic dev_info_t *
908178479Sjbprocess_devfunc(uchar_t bus, uchar_t dev, uchar_t func, uchar_t header,
909178479Sjb    ushort_t vendorid, int config_op)
910178479Sjb{
911178479Sjb	char nodename[32], unitaddr[5];
912178479Sjb	dev_info_t *dip;
913178479Sjb	uchar_t basecl, subcl, progcl, intr, revid;
914178479Sjb	ushort_t subvenid, subdevid, status;
915178479Sjb	ushort_t slot_num;
916178479Sjb	uint_t classcode, revclass;
917178479Sjb	int reprogram = 0, pciide = 0;
918178479Sjb	int power[2] = {1, 1};
919184696Srodrigc	int pciex = 0;
920184696Srodrigc	ushort_t is_pci_bridge = 0;
921184696Srodrigc
922184696Srodrigc	ushort_t deviceid = pci_getw(bus, dev, func, PCI_CONF_DEVID);
923184696Srodrigc
924184696Srodrigc	switch (header & PCI_HEADER_TYPE_M) {
925184696Srodrigc	case PCI_HEADER_ZERO:
926184696Srodrigc		subvenid = pci_getw(bus, dev, func, PCI_CONF_SUBVENID);
927184696Srodrigc		subdevid = pci_getw(bus, dev, func, PCI_CONF_SUBSYSID);
928184696Srodrigc		break;
929184696Srodrigc	case PCI_HEADER_CARDBUS:
930178479Sjb		subvenid = pci_getw(bus, dev, func, PCI_CBUS_SUBVENID);
931178479Sjb		subdevid = pci_getw(bus, dev, func, PCI_CBUS_SUBSYSID);
932178479Sjb		break;
933178479Sjb	default:
934178479Sjb		subvenid = 0;
935178479Sjb		subdevid = 0;
936178479Sjb		break;
937178479Sjb	}
938184696Srodrigc
939184696Srodrigc	if (config_op == CONFIG_FIX) {
940184696Srodrigc		if (vendorid == VENID_AMD && deviceid == DEVID_AMD8111_LPC) {
941184696Srodrigc			pci_fix_amd8111(bus, dev, func);
942184696Srodrigc		}
943184696Srodrigc		return (NULL);
944184696Srodrigc	}
945184696Srodrigc
946184696Srodrigc	/* XXX should be use generic names? derive from class? */
947184696Srodrigc	revclass = pci_getl(bus, dev, func, PCI_CONF_REVID);
948178479Sjb	classcode = revclass >> 8;
949178479Sjb	revid = revclass & 0xff;
950178479Sjb
951178479Sjb	/* figure out if this is pci-ide */
952178479Sjb	basecl = classcode >> 16;
953178479Sjb	subcl = (classcode >> 8) & 0xff;
954178479Sjb	progcl = classcode & 0xff;
955178479Sjb
956178479Sjb
957178479Sjb	if (is_display(classcode))
958178479Sjb		(void) snprintf(nodename, sizeof (nodename), "display");
959178479Sjb	else if (subvenid != 0)
960178479Sjb		(void) snprintf(nodename, sizeof (nodename),
961178479Sjb		    "pci%x,%x", subvenid, subdevid);
962178479Sjb	else
963178479Sjb		(void) snprintf(nodename, sizeof (nodename),
964178479Sjb		    "pci%x,%x", vendorid, deviceid);
965178479Sjb
966178573Sjb	/* make sure parent bus dip has been created */
967178479Sjb	if (pci_bus_res[bus].dip == NULL) {
968178573Sjb		create_root_bus_dip(bus);
969178479Sjb	}
970178479Sjb
971178479Sjb	ndi_devi_alloc_sleep(pci_bus_res[bus].dip, nodename,
972178479Sjb	    DEVI_SID_NODEID, &dip);
973178479Sjb
974178479Sjb	if (check_if_device_is_pciex(dip, bus, dev, func, &slot_num,
975178479Sjb	    &is_pci_bridge) == B_TRUE)
976178479Sjb		pciex = 1;
977178479Sjb
978178573Sjb	/* add properties */
979178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id", deviceid);
980178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id", vendorid);
981178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "revision-id", revid);
982178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
983178479Sjb	    "class-code", classcode);
984178479Sjb	if (func == 0)
985178479Sjb		(void) snprintf(unitaddr, sizeof (unitaddr), "%x", dev);
986178479Sjb	else
987178479Sjb		(void) snprintf(unitaddr, sizeof (unitaddr),
988178479Sjb		    "%x,%x", dev, func);
989178479Sjb	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
990178479Sjb	    "unit-address", unitaddr);
991178479Sjb
992178479Sjb	/* add device_type for display nodes */
993178479Sjb	if (is_display(classcode)) {
994178479Sjb		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
995178479Sjb		    "device_type", "display");
996178479Sjb	}
997178479Sjb	/* add special stuff for header type */
998178479Sjb	if ((header & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) {
999178479Sjb		uchar_t mingrant = pci_getb(bus, dev, func, PCI_CONF_MIN_G);
1000178479Sjb		uchar_t maxlatency = pci_getb(bus, dev, func, PCI_CONF_MAX_L);
1001178479Sjb
1002178573Sjb		if (subvenid != 0) {
1003178573Sjb			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1004178479Sjb			    "subsystem-id", subdevid);
1005178479Sjb			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1006178573Sjb			    "subsystem-vendor-id", subvenid);
1007178573Sjb		}
1008178573Sjb		if (!pciex)
1009178479Sjb			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1010178479Sjb			    "min-grant", mingrant);
1011178479Sjb		if (!pciex)
1012178479Sjb			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1013178573Sjb			    "max-latency", maxlatency);
1014178573Sjb	}
1015178479Sjb
1016178479Sjb	/* interrupt, record if not 0 */
1017178479Sjb	intr = pci_getb(bus, dev, func, PCI_CONF_IPIN);
1018178479Sjb	if (intr != 0)
1019178479Sjb		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1020178573Sjb		    "interrupts", intr);
1021178573Sjb
1022178479Sjb	/*
1023178479Sjb	 * Add support for 133 mhz pci eventually
1024178479Sjb	 */
1025178479Sjb	status = pci_getw(bus, dev, func, PCI_CONF_STAT);
1026178479Sjb
1027178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1028178573Sjb	    "devsel-speed", (status & PCI_STAT_DEVSELT) >> 9);
1029178573Sjb	if (!pciex && (status & PCI_STAT_FBBC))
1030178479Sjb		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
1031178573Sjb		    "fast-back-to-back");
1032178573Sjb	if (!pciex && (status & PCI_STAT_66MHZ))
1033178573Sjb		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
1034178479Sjb		    "66mhz-capable");
1035178479Sjb	if (status & PCI_STAT_UDF)
1036178479Sjb		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
1037178573Sjb		    "udf-supported");
1038178573Sjb	if (pciex && slot_num)
1039178479Sjb		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1040178479Sjb		    "physical-slot#", slot_num);
1041178479Sjb
1042178479Sjb	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1043178479Sjb	    "power-consumption", power, 2);
1044178479Sjb
1045178479Sjb	if ((basecl == PCI_CLASS_BRIDGE) && (subcl == PCI_BRIDGE_PCI))
1046178479Sjb		add_ppb_props(dip, bus, dev, func, pciex);
1047178573Sjb
1048178479Sjb	if (config_op == CONFIG_INFO &&
1049178479Sjb	    IS_CLASS_IOAPIC(basecl, subcl, progcl)) {
1050178479Sjb		create_ioapic_node(bus, dev, func, vendorid, deviceid);
1051178479Sjb	}
1052178479Sjb
1053178479Sjb	/* check for ck8-04 based PCI ISA bridge only */
1054178479Sjb	if (NVIDIA_IS_LPC_BRIDGE(vendorid, deviceid) && (dev == 1) &&
1055178479Sjb	    (func == 0))
1056178573Sjb		add_nvidia_isa_bridge_props(dip, bus, dev, func);
1057178479Sjb
1058178479Sjb	if (pciex && is_pci_bridge)
1059178479Sjb		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
1060178479Sjb		    (char *)"PCIe-PCI bridge");
1061178479Sjb	else
1062178573Sjb		add_model_prop(dip, classcode);
1063178479Sjb
1064178479Sjb	add_compatible(dip, subvenid, subdevid, vendorid, deviceid,
1065178479Sjb	    revid, classcode, pciex);
1066178479Sjb
1067178479Sjb	/*
1068178479Sjb	 * See if this device is a controller that advertises
1069178479Sjb	 * itself to be a standard ATA task file controller, or one that
1070178479Sjb	 * has been hard coded.
1071178479Sjb	 *
1072178479Sjb	 * If it is, check if any other higher precedence driver listed in
1073178479Sjb	 * driver_aliases will claim the node by calling
1074178479Sjb	 * ddi_compatibile_driver_major.  If so, clear pciide and do not
1075178479Sjb	 * create a pci-ide node or any other special handling.
1076178479Sjb	 *
1077178479Sjb	 * If another driver does not bind, set the node name to pci-ide
1078178479Sjb	 * and then let the special pci-ide handling for registers and
1079178479Sjb	 * child pci-ide nodes proceed below.
1080178479Sjb	 */
1081178479Sjb	if (is_pciide(basecl, subcl, revid, vendorid, deviceid,
1082178479Sjb	    subvenid, subdevid) == 1) {
1083178479Sjb		if (ddi_compatible_driver_major(dip, NULL) == (major_t)-1) {
1084178479Sjb			(void) ndi_devi_set_nodename(dip, "pci-ide", 0);
1085178479Sjb			pciide = 1;
1086178479Sjb		}
1087178479Sjb	}
1088178479Sjb
1089178479Sjb	reprogram = add_reg_props(dip, bus, dev, func, config_op, pciide);
1090178479Sjb	(void) ndi_devi_bind_driver(dip, 0);
1091178479Sjb
1092178479Sjb	/* special handling for pci-ide */
1093178479Sjb	if (pciide) {
1094178479Sjb		dev_info_t *cdip;
1095178479Sjb
1096178479Sjb		/*
1097178479Sjb		 * Create properties specified by P1275 Working Group
1098178479Sjb		 * Proposal #414 Version 1
1099178479Sjb		 */
1100178479Sjb		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1101178479Sjb		    "device_type", "pci-ide");
1102178479Sjb		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1103178479Sjb		    "#address-cells", 1);
1104178479Sjb		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1105178479Sjb		    "#size-cells", 0);
1106178479Sjb
1107178479Sjb		/* allocate two child nodes */
1108178479Sjb		ndi_devi_alloc_sleep(dip, "ide",
1109178479Sjb		    (pnode_t)DEVI_SID_NODEID, &cdip);
1110178479Sjb		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
1111178479Sjb		    "reg", 0);
1112178479Sjb		(void) ndi_devi_bind_driver(cdip, 0);
1113178479Sjb		ndi_devi_alloc_sleep(dip, "ide",
1114178479Sjb		    (pnode_t)DEVI_SID_NODEID, &cdip);
1115178479Sjb		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
1116178479Sjb		    "reg", 1);
1117178479Sjb		(void) ndi_devi_bind_driver(cdip, 0);
1118178479Sjb
1119178479Sjb		reprogram = 0;	/* don't reprogram pci-ide bridge */
1120178479Sjb	}
1121178479Sjb
1122178479Sjb
1123178479Sjb	if (reprogram)
1124178479Sjb		return (dip);
1125178479Sjb	return (NULL);
1126178479Sjb}
1127178479Sjb
1128178479Sjb/*
1129178479Sjb * Set the compatible property to a value compliant with
1130178479Sjb * rev 2.1 of the IEEE1275 PCI binding.
1131178479Sjb * (Also used for PCI-Express devices).
1132178479Sjb *
1133178479Sjb *   pciVVVV,DDDD.SSSS.ssss.RR	(0)
1134178479Sjb *   pciVVVV,DDDD.SSSS.ssss	(1)
1135178479Sjb *   pciSSSS,ssss		(2)
1136178479Sjb *   pciVVVV,DDDD.RR		(3)
1137178479Sjb *   pciVVVV,DDDD		(4)
1138178479Sjb *   pciclass,CCSSPP		(5)
1139178479Sjb *   pciclass,CCSS		(6)
1140178479Sjb *
1141178479Sjb * The Subsystem (SSSS) forms are not inserted if
1142178479Sjb * subsystem-vendor-id is 0.
1143178479Sjb *
1144178479Sjb * NOTE: For PCI-Express devices "pci" is replaced with "pciex" in 0-6 above
1145178479Sjb * property 2 is not created as per "1275 bindings for PCI Express Interconnect"
1146178479Sjb *
1147178479Sjb * Set with setprop and \x00 between each
1148178479Sjb * to generate the encoded string array form.
1149178479Sjb */
1150178479Sjbvoid
1151178479Sjbadd_compatible(dev_info_t *dip, ushort_t subvenid, ushort_t subdevid,
1152178479Sjb    ushort_t vendorid, ushort_t deviceid, uchar_t revid, uint_t classcode,
1153178479Sjb    int pciex)
1154178479Sjb{
1155178479Sjb	int i = 0;
1156178479Sjb	int size = COMPAT_BUFSIZE;
1157178573Sjb	char *compat[13];
1158178573Sjb	char *buf, *curr;
1159178573Sjb
1160178573Sjb	curr = buf = kmem_alloc(size, KM_SLEEP);
1161178573Sjb
1162178573Sjb	if (pciex) {
1163178573Sjb		if (subvenid) {
1164178479Sjb			compat[i++] = curr;	/* form 0 */
1165178479Sjb			(void) snprintf(curr, size, "pciex%x,%x.%x.%x.%x",
1166178479Sjb			    vendorid, deviceid, subvenid, subdevid, revid);
1167178479Sjb			size -= strlen(curr) + 1;
1168178479Sjb			curr += strlen(curr) + 1;
1169178479Sjb
1170178479Sjb			compat[i++] = curr;	/* form 1 */
1171178573Sjb			(void) snprintf(curr, size, "pciex%x,%x.%x.%x",
1172178573Sjb			    vendorid, deviceid, subvenid, subdevid);
1173178573Sjb			size -= strlen(curr) + 1;
1174178573Sjb			curr += strlen(curr) + 1;
1175178573Sjb
1176178573Sjb		}
1177178573Sjb		compat[i++] = curr;	/* form 3 */
1178178479Sjb		(void) snprintf(curr, size, "pciex%x,%x.%x",
1179178479Sjb		    vendorid, deviceid, revid);
1180178573Sjb		size -= strlen(curr) + 1;
1181178479Sjb		curr += strlen(curr) + 1;
1182178479Sjb
1183178479Sjb		compat[i++] = curr;	/* form 4 */
1184178479Sjb		(void) snprintf(curr, size, "pciex%x,%x", vendorid, deviceid);
1185178479Sjb		size -= strlen(curr) + 1;
1186178479Sjb		curr += strlen(curr) + 1;
1187178479Sjb
1188178479Sjb		compat[i++] = curr;	/* form 5 */
1189178479Sjb		(void) snprintf(curr, size, "pciexclass,%06x", classcode);
1190178479Sjb		size -= strlen(curr) + 1;
1191178479Sjb		curr += strlen(curr) + 1;
1192178479Sjb
1193178479Sjb		compat[i++] = curr;	/* form 6 */
1194178479Sjb		(void) snprintf(curr, size, "pciexclass,%04x",
1195178479Sjb		    (classcode >> 8));
1196178479Sjb		size -= strlen(curr) + 1;
1197178479Sjb		curr += strlen(curr) + 1;
1198178479Sjb	}
1199178479Sjb
1200178479Sjb	if (subvenid) {
1201178479Sjb		compat[i++] = curr;	/* form 0 */
1202178479Sjb		(void) snprintf(curr, size, "pci%x,%x.%x.%x.%x",
1203178479Sjb		    vendorid, deviceid, subvenid, subdevid, revid);
1204178479Sjb		size -= strlen(curr) + 1;
1205178479Sjb		curr += strlen(curr) + 1;
1206178479Sjb
1207178479Sjb		compat[i++] = curr;	/* form 1 */
1208178479Sjb		(void) snprintf(curr, size, "pci%x,%x.%x.%x",
1209178479Sjb		    vendorid, deviceid, subvenid, subdevid);
1210178479Sjb		size -= strlen(curr) + 1;
1211178479Sjb		curr += strlen(curr) + 1;
1212178479Sjb
1213178479Sjb		compat[i++] = curr;	/* form 2 */
1214178479Sjb		(void) snprintf(curr, size, "pci%x,%x", subvenid, subdevid);
1215178479Sjb		size -= strlen(curr) + 1;
1216178479Sjb		curr += strlen(curr) + 1;
1217178479Sjb	}
1218178479Sjb	compat[i++] = curr;	/* form 3 */
1219178479Sjb	(void) snprintf(curr, size, "pci%x,%x.%x", vendorid, deviceid, revid);
1220178479Sjb	size -= strlen(curr) + 1;
1221178479Sjb	curr += strlen(curr) + 1;
1222178479Sjb
1223178479Sjb	compat[i++] = curr;	/* form 4 */
1224178479Sjb	(void) snprintf(curr, size, "pci%x,%x", vendorid, deviceid);
1225178479Sjb	size -= strlen(curr) + 1;
1226178479Sjb	curr += strlen(curr) + 1;
1227178479Sjb
1228178479Sjb	compat[i++] = curr;	/* form 5 */
1229178479Sjb	(void) snprintf(curr, size, "pciclass,%06x", classcode);
1230178479Sjb	size -= strlen(curr) + 1;
1231178479Sjb	curr += strlen(curr) + 1;
1232178479Sjb
1233178479Sjb	compat[i++] = curr;	/* form 6 */
1234178479Sjb	(void) snprintf(curr, size, "pciclass,%04x", (classcode >> 8));
1235178479Sjb	size -= strlen(curr) + 1;
1236178479Sjb	curr += strlen(curr) + 1;
1237178479Sjb
1238178479Sjb	(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1239178479Sjb	    "compatible", compat, i);
1240178479Sjb	kmem_free(buf, COMPAT_BUFSIZE);
1241178479Sjb}
1242178479Sjb
1243178479Sjb/*
1244178479Sjb * Adjust the reg properties for a dual channel PCI-IDE device.
1245178479Sjb *
1246178479Sjb * NOTE: don't do anything that changes the order of the hard-decodes
1247178479Sjb * and programmed BARs. The kernel driver depends on these values
1248178479Sjb * being in this order regardless of whether they're for a 'native'
1249178479Sjb * mode BAR or not.
1250178479Sjb */
1251178479Sjb/*
1252178479Sjb * config info for pci-ide devices
1253178479Sjb */
1254178479Sjbstatic struct {
1255178479Sjb	uchar_t  native_mask;	/* 0 == 'compatibility' mode, 1 == native */
1256178479Sjb	uchar_t  bar_offset;	/* offset for alt status register */
1257178479Sjb	ushort_t addr;		/* compatibility mode base address */
1258178479Sjb	ushort_t length;	/* number of ports for this BAR */
1259178479Sjb} pciide_bar[] = {
1260178479Sjb	{ 0x01, 0, 0x1f0, 8 },	/* primary lower BAR */
1261178479Sjb	{ 0x01, 2, 0x3f6, 1 },	/* primary upper BAR */
1262178479Sjb	{ 0x04, 0, 0x170, 8 },	/* secondary lower BAR */
1263178479Sjb	{ 0x04, 2, 0x376, 1 }	/* secondary upper BAR */
1264178479Sjb};
1265178479Sjb
1266178479Sjbstatic int
1267178479SjbpciIdeAdjustBAR(uchar_t progcl, int index, uint_t *basep, uint_t *lenp)
1268178479Sjb{
1269178479Sjb	int hard_decode = 0;
1270178479Sjb
1271178479Sjb	/*
1272178479Sjb	 * Adjust the base and len for the BARs of the PCI-IDE
1273178479Sjb	 * device's primary and secondary controllers. The first
1274178479Sjb	 * two BARs are for the primary controller and the next
1275178479Sjb	 * two BARs are for the secondary controller. The fifth
1276178479Sjb	 * and sixth bars are never adjusted.
1277178479Sjb	 */
1278178479Sjb	if (index >= 0 && index <= 3) {
1279178479Sjb		*lenp = pciide_bar[index].length;
1280178479Sjb
1281178479Sjb		if (progcl & pciide_bar[index].native_mask) {
1282178479Sjb			*basep += pciide_bar[index].bar_offset;
1283178479Sjb		} else {
1284178479Sjb			*basep = pciide_bar[index].addr;
1285178479Sjb			hard_decode = 1;
1286178479Sjb		}
1287178479Sjb	}
1288178479Sjb
1289178479Sjb	/*
1290178479Sjb	 * if either base or len is zero make certain both are zero
1291178479Sjb	 */
1292178479Sjb	if (*basep == 0 || *lenp == 0) {
1293178479Sjb		*basep = 0;
1294178479Sjb		*lenp = 0;
1295178479Sjb		hard_decode = 0;
1296178479Sjb	}
1297178479Sjb
1298178479Sjb	return (hard_decode);
1299178479Sjb}
1300178479Sjb
1301178479Sjb
1302178479Sjb/*
1303178479Sjb * Add the "reg" and "assigned-addresses" property
1304178479Sjb */
1305178479Sjbstatic int
1306178479Sjbadd_reg_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
1307178479Sjb    int config_op, int pciide)
1308178479Sjb{
1309178479Sjb	uchar_t baseclass, subclass, progclass, header;
1310178479Sjb	ushort_t bar_sz;
1311178479Sjb	uint_t value = 0, len, devloc;
1312178479Sjb	uint_t base, base_hi, type;
1313178479Sjb	ushort_t offset, end;
1314178479Sjb	int max_basereg, j, reprogram = 0;
1315178479Sjb	uint_t phys_hi;
1316178479Sjb	struct memlist **io_res, **mres, **mem_res, **pmem_res;
1317178479Sjb	uint16_t cmd_reg;
1318178479Sjb
1319178479Sjb	pci_regspec_t regs[16] = {{0}};
1320178479Sjb	pci_regspec_t assigned[15] = {{0}};
1321178479Sjb	int nreg, nasgn, enable = 0;
1322178479Sjb
1323178479Sjb	io_res = &pci_bus_res[bus].io_ports;
1324178479Sjb	mem_res = &pci_bus_res[bus].mem_space;
1325178479Sjb	if (bus == 0)	/* for bus 0, there is only mem_space */
1326178479Sjb		pmem_res = mem_res;
1327178479Sjb	else
1328178479Sjb		pmem_res = &pci_bus_res[bus].pmem_space;
1329178479Sjb
1330178479Sjb	devloc = (uint_t)bus << 16 | (uint_t)dev << 11 | (uint_t)func << 8;
1331178479Sjb	regs[0].pci_phys_hi = devloc;
1332178479Sjb	nreg = 1;	/* rest of regs[0] is all zero */
1333178479Sjb	nasgn = 0;
1334178479Sjb
1335178479Sjb	baseclass = pci_getb(bus, dev, func, PCI_CONF_BASCLASS);
1336178479Sjb	subclass = pci_getb(bus, dev, func, PCI_CONF_SUBCLASS);
1337178479Sjb	progclass = pci_getb(bus, dev, func, PCI_CONF_PROGCLASS);
1338178479Sjb	header = pci_getb(bus, dev, func, PCI_CONF_HEADER) & PCI_HEADER_TYPE_M;
1339178479Sjb
1340178479Sjb	switch (header) {
1341178479Sjb	case PCI_HEADER_ZERO:
1342178479Sjb		max_basereg = PCI_BASE_NUM;
1343178479Sjb		break;
1344178479Sjb	case PCI_HEADER_PPB:
1345178479Sjb		max_basereg = PCI_BCNF_BASE_NUM;
1346178479Sjb		break;
1347178479Sjb	case PCI_HEADER_CARDBUS:
1348178479Sjb		max_basereg = PCI_CBUS_BASE_NUM;
1349178479Sjb		break;
1350178479Sjb	default:
1351178479Sjb		max_basereg = 0;
1352178479Sjb		break;
1353178479Sjb	}
1354178479Sjb
1355178479Sjb	/*
1356178479Sjb	 * Create the register property by saving the current
1357178479Sjb	 * value of the base register. Write 0xffffffff to the
1358178479Sjb	 * base register.  Read the value back to determine the
1359178479Sjb	 * required size of the address space.  Restore the base
1360178479Sjb	 * register contents.
1361178479Sjb	 *
1362178479Sjb	 * Do not disable I/O and memory access; this isn't necessary
1363178479Sjb	 * since no driver is yet attached to this device, and disabling
1364178479Sjb	 * I/O and memory access has the side-effect of disabling PCI-PCI
1365178479Sjb	 * bridge mappings, which makes the bridge transparent to secondary-
1366178479Sjb	 * bus activity (see sections 4.1-4.3 of the PCI-PCI Bridge
1367178479Sjb	 * Spec V1.2).
1368178479Sjb	 */
1369178479Sjb	end = PCI_CONF_BASE0 + max_basereg * sizeof (uint_t);
1370178479Sjb	for (j = 0, offset = PCI_CONF_BASE0; offset < end;
1371178479Sjb	    j++, offset += bar_sz) {
1372178479Sjb		int hard_decode = 0;
1373178479Sjb
1374178479Sjb		/* determine the size of the address space */
1375178479Sjb		base = pci_getl(bus, dev, func, offset);
1376178479Sjb		pci_putl(bus, dev, func, offset, 0xffffffff);
1377178479Sjb		value = pci_getl(bus, dev, func, offset);
1378178479Sjb		pci_putl(bus, dev, func, offset, base);
1379178479Sjb
1380178479Sjb		/* construct phys hi,med.lo, size hi, lo */
1381178479Sjb		if ((pciide && j < 4) || (base & PCI_BASE_SPACE_IO)) {
1382178479Sjb			/* i/o space */
1383178479Sjb			bar_sz = PCI_BAR_SZ_32;
1384178479Sjb			value &= PCI_BASE_IO_ADDR_M;
1385178479Sjb			len = ((value ^ (value-1)) + 1) >> 1;
1386178479Sjb
1387178479Sjb			/* XXX Adjust first 4 IDE registers */
1388178479Sjb			if (pciide) {
1389178479Sjb				if (subclass != PCI_MASS_IDE)
1390178479Sjb					progclass = (PCI_IDE_IF_NATIVE_PRI |
1391178479Sjb					    PCI_IDE_IF_NATIVE_SEC);
1392178479Sjb				hard_decode = pciIdeAdjustBAR(progclass, j,
1393178479Sjb				    &base, &len);
1394178479Sjb			} else if (value == 0) {
1395178479Sjb				/* skip base regs with size of 0 */
1396178479Sjb				continue;
1397178479Sjb			}
1398178479Sjb
1399178479Sjb			regs[nreg].pci_size_low =
1400178479Sjb			    assigned[nasgn].pci_size_low = len;
1401178479Sjb			if (!hard_decode) {
1402178479Sjb				regs[nreg].pci_phys_hi =
1403178479Sjb				    (PCI_ADDR_IO | devloc) + offset;
1404178479Sjb			} else {
1405178479Sjb				regs[nreg].pci_phys_hi =
1406178479Sjb				    (PCI_RELOCAT_B | PCI_ADDR_IO | devloc) +
1407178479Sjb				    offset;
1408178479Sjb				regs[nreg].pci_phys_low =
1409178479Sjb				    base & PCI_BASE_IO_ADDR_M;
1410178479Sjb			}
1411178479Sjb			assigned[nasgn].pci_phys_hi =
1412178479Sjb			    (PCI_RELOCAT_B | PCI_ADDR_IO | devloc) + offset;
1413178479Sjb			type = base & (~PCI_BASE_IO_ADDR_M);
1414178479Sjb			base &= PCI_BASE_IO_ADDR_M;
1415178479Sjb
1416178479Sjb			/*
1417178479Sjb			 * first pass - gather what's there
1418178479Sjb			 * update/second pass - adjust/allocate regions
1419178479Sjb			 *	config - allocate regions
1420178479Sjb			 */
1421178479Sjb			if (config_op == CONFIG_INFO) {	/* first pass */
1422178479Sjb				/* take out of the resource map of the bus */
1423178479Sjb				if (*io_res && base != 0)
1424178479Sjb					(void) memlist_remove(io_res,
1425178479Sjb					    (uint64_t)base, (uint64_t)len);
1426178479Sjb				else if (*io_res)
1427178479Sjb					reprogram = 1;
1428178479Sjb			} else if (*io_res && base == 0) {
1429178479Sjb				base = (uint_t)memlist_find(io_res,
1430178479Sjb				    (uint64_t)len, (uint64_t)0x4);
1431178479Sjb				if (base != 0) {
1432178479Sjb					/* XXX need to worry about 64-bit? */
1433178479Sjb					pci_putl(bus, dev, func, offset,
1434178479Sjb					    base | type);
1435178479Sjb					base = pci_getl(bus, dev, func, offset);
1436178479Sjb					base &= PCI_BASE_IO_ADDR_M;
1437178479Sjb				}
1438178479Sjb				if (base == 0) {
1439178479Sjb					cmn_err(CE_WARN, "failed to program"
1440178479Sjb					    " IO space [%d/%d/%d] BAR@0x%x"
1441178479Sjb					    " length 0x%x",
1442178479Sjb					    bus, dev, func, offset, len);
1443178479Sjb				} else
1444178479Sjb					enable |= PCI_COMM_IO;
1445178479Sjb			}
1446178479Sjb			assigned[nasgn].pci_phys_low = base;
1447178479Sjb			nreg++, nasgn++;
1448178479Sjb
1449178479Sjb		} else {
1450178479Sjb			/* memory space */
1451178479Sjb			if ((base & PCI_BASE_TYPE_M) == PCI_BASE_TYPE_ALL) {
1452178479Sjb				bar_sz = PCI_BAR_SZ_64;
1453178479Sjb				base_hi = pci_getl(bus, dev, func, offset + 4);
1454178479Sjb				phys_hi = PCI_ADDR_MEM64;
1455178479Sjb			} else {
1456178479Sjb				bar_sz = PCI_BAR_SZ_32;
1457178479Sjb				base_hi = 0;
1458178479Sjb				phys_hi = PCI_ADDR_MEM32;
1459178479Sjb			}
1460178479Sjb
1461178479Sjb			/* skip base regs with size of 0 */
1462178479Sjb			value &= PCI_BASE_M_ADDR_M;
1463178479Sjb
1464178479Sjb			if (value == 0) {
1465178479Sjb				continue;
1466178479Sjb			}
1467178479Sjb			len = ((value ^ (value-1)) + 1) >> 1;
1468178479Sjb			regs[nreg].pci_size_low =
1469178479Sjb			    assigned[nasgn].pci_size_low = len;
1470178479Sjb
1471178479Sjb			phys_hi |= (devloc | offset);
1472178479Sjb			if (base & PCI_BASE_PREF_M) {
1473178479Sjb				mres = pmem_res;
1474178479Sjb				phys_hi |= PCI_PREFETCH_B;
1475178479Sjb			} else {
1476178479Sjb				mres = mem_res;
1477178479Sjb			}
1478178479Sjb			regs[nreg].pci_phys_hi =
1479178479Sjb			    assigned[nasgn].pci_phys_hi = phys_hi;
1480178479Sjb			assigned[nasgn].pci_phys_hi |= PCI_RELOCAT_B;
1481178479Sjb			assigned[nasgn].pci_phys_mid = base_hi;
1482178479Sjb			type = base & ~PCI_BASE_M_ADDR_M;
1483178479Sjb			base &= PCI_BASE_M_ADDR_M;
1484178479Sjb
1485178479Sjb			if (config_op == CONFIG_INFO) {
1486178479Sjb				/* take out of the resource map of the bus */
1487178479Sjb				if (*mres && base != 0) {
1488178479Sjb					(void) memlist_remove(mres,
1489178479Sjb					    (uint64_t)base, (uint64_t)len);
1490178479Sjb				} else if (*mres)
1491178479Sjb					reprogram = 1;
1492178479Sjb			} else if (*mres && base == 0) {
1493178479Sjb				base = (uint_t)memlist_find(mres,
1494178479Sjb				    (uint64_t)len, (uint64_t)0x1000);
1495178479Sjb				if (base != NULL) {
1496178479Sjb					pci_putl(bus, dev, func, offset,
1497178479Sjb					    base | type);
1498178479Sjb					base = pci_getl(bus, dev, func, offset);
1499178479Sjb					base &= PCI_BASE_M_ADDR_M;
1500178479Sjb				}
1501178479Sjb
1502178479Sjb				if (base == 0) {
1503178479Sjb					cmn_err(CE_WARN, "failed to program "
1504178479Sjb					    "mem space [%d/%d/%d] BAR@0x%x"
1505178479Sjb					    " length 0x%x",
1506178479Sjb					    bus, dev, func, offset, len);
1507178479Sjb				} else
1508178479Sjb					enable |= PCI_COMM_MAE;
1509178479Sjb			}
1510178479Sjb			assigned[nasgn].pci_phys_low = base;
1511178479Sjb			nreg++, nasgn++;
1512178479Sjb		}
1513178479Sjb	}
1514178479Sjb	switch (header) {
1515178479Sjb	case PCI_HEADER_ZERO:
1516178479Sjb		offset = PCI_CONF_ROM;
1517178479Sjb		break;
1518178479Sjb	case PCI_HEADER_PPB:
1519178479Sjb		offset = PCI_BCNF_ROM;
1520178479Sjb		break;
1521178479Sjb	default: /* including PCI_HEADER_CARDBUS */
1522178479Sjb		goto done;
1523178479Sjb	}
1524211554Srpaulo
1525178479Sjb	/*
1526178479Sjb	 * Add the expansion rom memory space
1527178479Sjb	 * Determine the size of the ROM base reg; don't write reserved bits
1528178479Sjb	 * ROM isn't in the PCI memory space.
1529178479Sjb	 */
1530178479Sjb	base = pci_getl(bus, dev, func, offset);
1531211554Srpaulo	pci_putl(bus, dev, func, offset, PCI_BASE_ROM_ADDR_M);
1532211554Srpaulo	value = pci_getl(bus, dev, func, offset);
1533211554Srpaulo	pci_putl(bus, dev, func, offset, base);
1534211554Srpaulo	if (value & PCI_BASE_ROM_ENABLE)
1535211554Srpaulo		value &= PCI_BASE_ROM_ADDR_M;
1536211554Srpaulo	else
1537211554Srpaulo		value = 0;
1538211554Srpaulo
1539211554Srpaulo	if (value != 0) {
1540211554Srpaulo		regs[nreg].pci_phys_hi = (PCI_ADDR_MEM32 | devloc) + offset;
1541211554Srpaulo		assigned[nasgn].pci_phys_hi = (PCI_RELOCAT_B |
1542211554Srpaulo		    PCI_ADDR_MEM32 | devloc) + offset;
1543211554Srpaulo		base &= PCI_BASE_ROM_ADDR_M;
1544211554Srpaulo		assigned[nasgn].pci_phys_low = base;
1545211554Srpaulo		len = ((value ^ (value-1)) + 1) >> 1;
1546211554Srpaulo		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = len;
1547178479Sjb		nreg++, nasgn++;
1548178479Sjb		/* take it out of the memory resource */
1549178479Sjb		if (*mem_res && base != 0)
1550178479Sjb			(void) memlist_remove(mem_res,
1551178479Sjb			    (uint64_t)base, (uint64_t)len);
1552178479Sjb	}
1553178479Sjb
1554178479Sjb	/*
1555178479Sjb	 * The following are ISA resources. There are not part
1556178479Sjb	 * of the PCI local bus resources. So don't attempt to
1557178479Sjb	 * do resource accounting against PCI.
1558211554Srpaulo	 */
1559211554Srpaulo
1560211554Srpaulo	/* add the three hard-decode, aliased address spaces for VGA */
1561178479Sjb	if ((baseclass == PCI_CLASS_DISPLAY && subclass == PCI_DISPLAY_VGA) ||
1562178479Sjb	    (baseclass == PCI_CLASS_NONE && subclass == PCI_NONE_VGA)) {
1563178479Sjb
1564178479Sjb		/* VGA hard decode 0x3b0-0x3bb */
1565178479Sjb		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
1566178479Sjb		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
1567178479Sjb		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x3b0;
1568178479Sjb		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0xc;
1569178479Sjb		nreg++, nasgn++;
1570178479Sjb
1571178479Sjb		/* VGA hard decode 0x3c0-0x3df */
1572178479Sjb		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
1573178479Sjb		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
1574211554Srpaulo		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x3c0;
1575211554Srpaulo		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0x20;
1576211554Srpaulo		nreg++, nasgn++;
1577178479Sjb
1578178479Sjb		/* Video memory */
1579178479Sjb		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
1580178479Sjb		    (PCI_RELOCAT_B | PCI_ADDR_MEM32 | devloc);
1581178479Sjb		regs[nreg].pci_phys_low =
1582178479Sjb		    assigned[nasgn].pci_phys_low = 0xa0000;
1583178479Sjb		regs[nreg].pci_size_low =
1584178479Sjb		    assigned[nasgn].pci_size_low = 0x20000;
1585178479Sjb		nreg++, nasgn++;
1586178479Sjb	}
1587178479Sjb
1588178479Sjb	/* add the hard-decode, aliased address spaces for 8514 */
1589178479Sjb	if ((baseclass == PCI_CLASS_DISPLAY) &&
1590178479Sjb	    (subclass == PCI_DISPLAY_VGA) &&
1591178479Sjb	    (progclass & PCI_DISPLAY_IF_8514)) {
1592178479Sjb
1593178479Sjb		/* hard decode 0x2e8 */
1594178479Sjb		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
1595178573Sjb		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
1596178573Sjb		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x2e8;
1597211554Srpaulo		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0x1;
1598211554Srpaulo		nreg++, nasgn++;
1599211554Srpaulo
1600211554Srpaulo		/* hard decode 0x2ea-0x2ef */
1601211554Srpaulo		regs[nreg].pci_phys_hi = assigned[nasgn].pci_phys_hi =
1602211554Srpaulo		    (PCI_RELOCAT_B | PCI_ALIAS_B | PCI_ADDR_IO | devloc);
1603211554Srpaulo		regs[nreg].pci_phys_low = assigned[nasgn].pci_phys_low = 0x2ea;
1604211554Srpaulo		regs[nreg].pci_size_low = assigned[nasgn].pci_size_low = 0x6;
1605211554Srpaulo		nreg++, nasgn++;
1606211554Srpaulo	}
1607211554Srpaulo
1608211554Srpaulodone:
1609211554Srpaulo	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
1610178573Sjb	    (int *)regs, nreg * sizeof (pci_regspec_t) / sizeof (int));
1611178479Sjb	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1612178479Sjb	    "assigned-addresses",
1613178479Sjb	    (int *)assigned, nasgn * sizeof (pci_regspec_t) / sizeof (int));
1614178479Sjb	if (config_op == CONFIG_NEW && enable) {
1615178479Sjb		cmn_err(CE_NOTE,
1616178479Sjb		    "!enable PCI device [%d/%d/%d]", bus, dev, func);
1617178479Sjb		cmd_reg = pci_getw(bus, dev, func, PCI_CONF_COMM);
1618178573Sjb		cmd_reg |= (enable | PCI_COMM_ME);
1619178573Sjb		pci_putw(bus, dev, func, PCI_CONF_COMM, cmd_reg);
1620178573Sjb	}
1621178573Sjb	return (reprogram);
1622178573Sjb}
1623178479Sjb
1624178479Sjbstatic void
1625178479Sjbadd_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
1626178479Sjb    int pciex)
1627178479Sjb{
1628178479Sjb	char *dev_type;
1629178479Sjb	int i;
1630178479Sjb	uint_t val, io_range[2], mem_range[2], pmem_range[2];
1631178479Sjb	uchar_t secbus = pci_getb(bus, dev, func, PCI_BCNF_SECBUS);
1632178479Sjb	uchar_t subbus = pci_getb(bus, dev, func, PCI_BCNF_SUBBUS);
1633178479Sjb	ASSERT(secbus <= subbus);
1634178479Sjb
1635178479Sjb	/*
1636178479Sjb	 * Some BIOSes lie about max pci busses, we allow for
1637178479Sjb	 * such mistakes here
1638178479Sjb	 */
1639178479Sjb	if (subbus > pci_bios_nbus) {
1640178479Sjb		pci_bios_nbus = subbus;
1641178479Sjb		alloc_res_array();
1642178479Sjb	}
1643178479Sjb
1644178479Sjb	ASSERT(pci_bus_res[secbus].dip == NULL);
1645178479Sjb	pci_bus_res[secbus].dip = dip;
1646178479Sjb	pci_bus_res[secbus].par_bus = bus;
1647178479Sjb
1648178479Sjb	dev_type = pciex ? "pciex" : "pci";
1649178479Sjb
1650178479Sjb	/* setup bus number hierarchy */
1651178479Sjb	pci_bus_res[secbus].sub_bus = subbus;
1652178479Sjb	/*
1653178479Sjb	 * Keep track of the largest subordinate bus number (this is essential
1654178479Sjb	 * for peer busses because there is no other way of determining its
1655178479Sjb	 * subordinate bus number).
1656178479Sjb	 */
1657178479Sjb	if (subbus > pci_bus_res[bus].sub_bus)
1658178479Sjb		pci_bus_res[bus].sub_bus = subbus;
1659178479Sjb	/*
1660178479Sjb	 * Loop through subordinate busses, initializing their parent bus
1661178479Sjb	 * field to this bridge's parent.  The subordinate busses' parent
1662178479Sjb	 * fields may very well be further refined later, as child bridges
1663178479Sjb	 * are enumerated.  (The value is to note that the subordinate busses
1664178479Sjb	 * are not peer busses by changing their par_bus fields to anything
1665178479Sjb	 * other than -1.)
1666178479Sjb	 */
1667178479Sjb	for (i = secbus + 1; i <= subbus; i++)
1668178479Sjb		pci_bus_res[i].par_bus = bus;
1669178479Sjb
1670178479Sjb	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1671178479Sjb	    "device_type", dev_type);
1672178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1673178479Sjb	    "#address-cells", 3);
1674178479Sjb	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1675178479Sjb	    "#size-cells", 2);
1676178479Sjb
1677178479Sjb	/*
1678178479Sjb	 * According to PPB spec, the base register should be programmed
1679178479Sjb	 * with a value bigger than the limit register when there are
1680178479Sjb	 * no resources available. This applies to io, memory, and
1681178479Sjb	 * prefetchable memory.
1682178479Sjb	 */
1683178479Sjb
1684178573Sjb	/*
1685178479Sjb	 * io range
1686178479Sjb	 * We determine i/o windows that are left unconfigured by bios
1687178479Sjb	 * through its i/o enable bit as Microsoft recommends OEMs to do.
1688178479Sjb	 * If it is unset, we disable i/o and mark it for reconfiguration in
1689178479Sjb	 * later passes by setting the base > limit
1690178479Sjb	 */
1691178479Sjb	val = (uint_t)pci_getw(bus, dev, func, PCI_CONF_COMM);
1692178479Sjb	if (val & PCI_COMM_IO) {
1693178479Sjb		val = (uint_t)pci_getb(bus, dev, func, PCI_BCNF_IO_BASE_LOW);
1694178573Sjb		io_range[0] = ((val & 0xf0) << 8);
1695178573Sjb		val = (uint_t)pci_getb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW);
1696178573Sjb		io_range[1]  = ((val & 0xf0) << 8) | 0xFFF;
1697178573Sjb	} else {
1698178573Sjb		io_range[0] = 0x9fff;
1699178479Sjb		io_range[1] = 0x1000;
1700178479Sjb		pci_putb(bus, dev, func, PCI_BCNF_IO_BASE_LOW,
1701178479Sjb		    (uint8_t)((io_range[0] >> 8) & 0xf0));
1702178479Sjb		pci_putb(bus, dev, func, PCI_BCNF_IO_LIMIT_LOW,
1703178479Sjb		    (uint8_t)((io_range[1] >> 8) & 0xf0));
1704178479Sjb		pci_putw(bus, dev, func, PCI_BCNF_IO_BASE_HI, 0);
1705178479Sjb		pci_putw(bus, dev, func, PCI_BCNF_IO_LIMIT_HI, 0);
1706178479Sjb	}
1707178479Sjb
1708178479Sjb	if (io_range[0] != 0 && io_range[0] < io_range[1]) {
1709178479Sjb		memlist_insert(&pci_bus_res[secbus].io_ports,
1710178479Sjb		    (uint64_t)io_range[0],
1711178479Sjb		    (uint64_t)(io_range[1] - io_range[0] + 1));
1712178479Sjb		if (pci_bus_res[bus].io_ports != NULL) {
1713178479Sjb			(void) memlist_remove(&pci_bus_res[bus].io_ports,
1714178479Sjb			    (uint64_t)io_range[0],
1715178479Sjb			    (uint64_t)(io_range[1] - io_range[0] + 1));
1716178479Sjb		}
1717178479Sjb		dcmn_err(CE_NOTE, "bus %d io-range: 0x%x-%x",
1718178479Sjb		    secbus, io_range[0], io_range[1]);
1719178479Sjb		/* if 32-bit supported, make sure upper bits are not set */
1720178479Sjb		if ((val & 0xf) == 1 &&
1721178479Sjb		    pci_getw(bus, dev, func, PCI_BCNF_IO_BASE_HI)) {
1722178479Sjb			cmn_err(CE_NOTE, "unsupported 32-bit IO address on"
1723178479Sjb			    " pci-pci bridge [%d/%d/%d]", bus, dev, func);
1724178479Sjb		}
1725178479Sjb	}
1726178479Sjb
1727178479Sjb	/* mem range */
1728178573Sjb	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_BASE);
1729178479Sjb	mem_range[0] = ((val & 0xFFF0) << 16);
1730178479Sjb	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_MEM_LIMIT);
1731178573Sjb	mem_range[1] = ((val & 0xFFF0) << 16) | 0xFFFFF;
1732178479Sjb	if (mem_range[0] != 0 && mem_range[0] < mem_range[1]) {
1733211554Srpaulo		memlist_insert(&pci_bus_res[secbus].mem_space,
1734178479Sjb		    (uint64_t)mem_range[0],
1735178479Sjb		    (uint64_t)(mem_range[1] - mem_range[0] + 1));
1736178479Sjb		/* remove from parent resouce list */
1737178479Sjb		if (pci_bus_res[bus].mem_space != NULL) {
1738178479Sjb			(void) memlist_remove(&pci_bus_res[bus].mem_space,
1739178479Sjb			    (uint64_t)mem_range[0],
1740211554Srpaulo			    (uint64_t)(mem_range[1] - mem_range[0] + 1));
1741211554Srpaulo		}
1742211554Srpaulo		dcmn_err(CE_NOTE, "bus %d mem-range: 0x%x-%x",
1743211554Srpaulo		    secbus, mem_range[0], mem_range[1]);
1744178479Sjb	}
1745178479Sjb
1746178479Sjb	/* prefetchable memory range */
1747178479Sjb	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_PF_BASE_LOW);
1748178479Sjb	pmem_range[0] = ((val & 0xFFF0) << 16);
1749178573Sjb	val = (uint_t)pci_getw(bus, dev, func, PCI_BCNF_PF_LIMIT_LOW);
1750178479Sjb	pmem_range[1] = ((val & 0xFFF0) << 16) | 0xFFFFF;
1751178479Sjb	if (pmem_range[0] != 0 && pmem_range[0] < pmem_range[1]) {
1752178479Sjb		memlist_insert(&pci_bus_res[secbus].pmem_space,
1753178479Sjb		    (uint64_t)pmem_range[0],
1754178479Sjb		    (uint64_t)(pmem_range[1] - pmem_range[0] + 1));
1755178479Sjb		if (pci_bus_res[bus].pmem_space != NULL) {
1756178479Sjb			(void) memlist_remove(&pci_bus_res[bus].pmem_space,
1757178479Sjb			    (uint64_t)pmem_range[0],
1758178479Sjb			    (uint64_t)(pmem_range[1] - pmem_range[0] + 1));
1759178479Sjb		}
1760178479Sjb		dcmn_err(CE_NOTE, "bus %d pmem-range: 0x%x-%x",
1761178479Sjb		    secbus, pmem_range[0], pmem_range[1]);
1762178479Sjb		/* if 64-bit supported, make sure upper bits are not set */
1763178479Sjb		if ((val & 0xf) == 1 &&
1764178479Sjb		    pci_getl(bus, dev, func, PCI_BCNF_PF_BASE_HIGH)) {
1765178479Sjb			cmn_err(CE_NOTE, "unsupported 64-bit prefetch memory on"
1766178573Sjb			    " pci-pci bridge [%d/%d/%d]", bus, dev, func);
1767211554Srpaulo		}
1768178479Sjb	}
1769178573Sjb
1770178573Sjb	add_bus_range_prop(secbus);
1771178573Sjb	add_ppb_ranges_prop(secbus);
1772178573Sjb}
1773178573Sjb
1774178573Sjbextern const struct pci_class_strings_s class_pci[];
1775178573Sjbextern int class_pci_items;
1776178573Sjb
1777178573Sjbstatic void
1778178573Sjbadd_model_prop(dev_info_t *dip, uint_t classcode)
1779178573Sjb{
1780178573Sjb	const char *desc;
1781178573Sjb	int i;
1782178573Sjb	uchar_t baseclass = classcode >> 16;
1783178573Sjb	uchar_t subclass = (classcode >> 8) & 0xff;
1784187347Sjhb	uchar_t progclass = classcode & 0xff;
1785178573Sjb
1786178573Sjb	if ((baseclass == PCI_CLASS_MASS) && (subclass == PCI_MASS_IDE)) {
1787178573Sjb		desc = "IDE controller";
1788178573Sjb	} else {
1789211554Srpaulo		for (desc = 0, i = 0; i < class_pci_items; i++) {
1790211554Srpaulo			if ((baseclass == class_pci[i].base_class) &&
1791211554Srpaulo			    (subclass == class_pci[i].sub_class) &&
1792178573Sjb			    (progclass == class_pci[i].prog_class)) {
1793178573Sjb				desc = class_pci[i].actual_desc;
1794211554Srpaulo				break;
1795211554Srpaulo			}
1796178573Sjb		}
1797178479Sjb		if (i == class_pci_items)
1798178479Sjb			desc = "Unknown class of pci/pnpbios device";
1799178479Sjb	}
1800178479Sjb
1801178479Sjb	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
1802178479Sjb	    (char *)desc);
1803178479Sjb}
1804178479Sjb
1805178479Sjbstatic void
1806178479Sjbadd_bus_range_prop(int bus)
1807178479Sjb{
1808178479Sjb	int bus_range[2];
1809178479Sjb
1810178479Sjb	if (pci_bus_res[bus].dip == NULL)
1811178479Sjb		return;
1812178479Sjb	bus_range[0] = bus;
1813178479Sjb	bus_range[1] = pci_bus_res[bus].sub_bus;
1814178479Sjb	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, pci_bus_res[bus].dip,
1815178479Sjb	    "bus-range", (int *)bus_range, 2);
1816178479Sjb}
1817211554Srpaulo
1818211554Srpaulo/*
1819211554Srpaulo * Add slot-names property for any named pci hot-plug slots
1820211554Srpaulo */
1821211554Srpaulostatic void
1822211554Srpauloadd_bus_slot_names_prop(int bus)
1823211554Srpaulo{
1824211554Srpaulo	char slotprop[256];
1825211554Srpaulo	int len;
1826211554Srpaulo
1827211554Srpaulo	len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop));
1828211554Srpaulo	if (len > 0) {
1829211554Srpaulo		/*
1830211554Srpaulo		 * Only create a peer bus node if this bus may be a peer bus.
1831211554Srpaulo		 * It may be a peer bus if the dip is NULL and if par_bus is
1832211554Srpaulo		 * -1 (par_bus is -1 if this bus was not found to be
1833211554Srpaulo		 * subordinate to any PCI-PCI bridge).
1834211554Srpaulo		 * If it's not a peer bus, then the ACPI BBN-handling code
1835211554Srpaulo		 * will remove it later.
1836211554Srpaulo		 */
1837211554Srpaulo		if (pci_bus_res[bus].par_bus == (uchar_t)-1 &&
1838211554Srpaulo		    pci_bus_res[bus].dip == NULL) {
1839211554Srpaulo
1840211554Srpaulo			create_root_bus_dip(bus);
1841211554Srpaulo		}
1842211554Srpaulo		if (pci_bus_res[bus].dip != NULL) {
1843211554Srpaulo			ASSERT((len % sizeof (int)) == 0);
1844211554Srpaulo			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
1845211554Srpaulo			    pci_bus_res[bus].dip, "slot-names",
1846211554Srpaulo			    (int *)slotprop, len / sizeof (int));
1847211554Srpaulo		} else {
1848211554Srpaulo			cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI "
1849211554Srpaulo			    "IRQ routing table; Not adding slot-names "
1850211554Srpaulo			    "property for incorrect bus %d", bus);
1851211554Srpaulo		}
1852211554Srpaulo	}
1853211554Srpaulo}
1854211554Srpaulo
1855211554Srpaulostatic int
1856211554Srpaulomemlist_to_range(ppb_ranges_t *rp, struct memlist *entry, int type)
1857211554Srpaulo{
1858211554Srpaulo	if (entry == NULL)
1859211554Srpaulo		return (0);
1860211554Srpaulo
1861211554Srpaulo	/* assume 32-bit addresses */
1862211554Srpaulo	rp->child_high = rp->parent_high = type;
1863211554Srpaulo	rp->child_mid = rp->parent_mid = 0;
1864211554Srpaulo	rp->child_low = rp->parent_low = (uint32_t)entry->address;
1865211554Srpaulo	rp->size_high = 0;
1866211554Srpaulo	rp->size_low = (uint32_t)entry->size;
1867211554Srpaulo	return (1);
1868211554Srpaulo}
1869211554Srpaulo
1870211554Srpaulostatic void
1871211554Srpauloadd_ppb_ranges_prop(int bus)
1872211554Srpaulo{
1873211554Srpaulo	int i = 0;
1874211554Srpaulo	ppb_ranges_t *rp;
1875211554Srpaulo
1876211554Srpaulo	rp = kmem_alloc(3 * sizeof (*rp), KM_SLEEP);
1877211554Srpaulo
1878211554Srpaulo	i = memlist_to_range(&rp[0], pci_bus_res[bus].io_ports,
1879211554Srpaulo	    PCI_ADDR_IO | PCI_REG_REL_M);
1880211554Srpaulo	i += memlist_to_range(&rp[i], pci_bus_res[bus].mem_space,
1881211554Srpaulo	    PCI_ADDR_MEM32 | PCI_REG_REL_M);
1882211554Srpaulo	i += memlist_to_range(&rp[i], pci_bus_res[bus].pmem_space,
1883211554Srpaulo	    PCI_ADDR_MEM32 | PCI_REG_REL_M | PCI_REG_PF_M);
1884211554Srpaulo
1885211554Srpaulo	if (i != 0)
1886211554Srpaulo		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
1887211554Srpaulo		    pci_bus_res[bus].dip, "ranges", (int *)rp,
1888211554Srpaulo		    i * sizeof (ppb_ranges_t) / sizeof (int));
1889211554Srpaulo	kmem_free(rp, 3 * sizeof (*rp));
1890211554Srpaulo}
1891211554Srpaulo
1892211554Srpaulostatic int
1893211554Srpaulomemlist_to_spec(struct pci_phys_spec *sp, struct memlist *list, int type)
1894211554Srpaulo{
1895211554Srpaulo	int i = 0;
1896211554Srpaulo
1897211554Srpaulo	while (list) {
1898211554Srpaulo		/* assume 32-bit addresses */
1899211554Srpaulo		sp->pci_phys_hi = type;
1900211554Srpaulo		sp->pci_phys_mid = 0;
1901211554Srpaulo		sp->pci_phys_low = (uint32_t)list->address;
1902211554Srpaulo		sp->pci_size_hi = 0;
1903211554Srpaulo		sp->pci_size_low = (uint32_t)list->size;
1904211554Srpaulo
1905211554Srpaulo		list = list->next;
1906211554Srpaulo		sp++, i++;
1907211554Srpaulo	}
1908211554Srpaulo	return (i);
1909211554Srpaulo}
1910211554Srpaulo
1911211554Srpaulostatic void
1912211554Srpauloadd_bus_available_prop(int bus)
1913211554Srpaulo{
1914211554Srpaulo	int i, count;
1915211554Srpaulo	struct pci_phys_spec *sp;
1916211554Srpaulo
1917211554Srpaulo	count = memlist_count(pci_bus_res[bus].io_ports) +
1918211554Srpaulo	    memlist_count(pci_bus_res[bus].mem_space) +
1919211554Srpaulo	    memlist_count(pci_bus_res[bus].pmem_space);
1920211554Srpaulo
1921211554Srpaulo	if (count == 0)		/* nothing available */
1922211554Srpaulo		return;
1923211554Srpaulo
1924211554Srpaulo	sp = kmem_alloc(count * sizeof (*sp), KM_SLEEP);
1925211554Srpaulo	i = memlist_to_spec(&sp[0], pci_bus_res[bus].io_ports,
1926211554Srpaulo	    PCI_ADDR_IO | PCI_REG_REL_M);
1927211554Srpaulo	i += memlist_to_spec(&sp[i], pci_bus_res[bus].mem_space,
1928211554Srpaulo	    PCI_ADDR_MEM32 | PCI_REG_REL_M);
1929211554Srpaulo	i += memlist_to_spec(&sp[i], pci_bus_res[bus].pmem_space,
1930211554Srpaulo	    PCI_ADDR_MEM32 | PCI_REG_REL_M | PCI_REG_PF_M);
1931211554Srpaulo	ASSERT(i == count);
1932211554Srpaulo
1933211554Srpaulo	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, pci_bus_res[bus].dip,
1934211554Srpaulo	    "available", (int *)sp,
1935211554Srpaulo	    i * sizeof (struct pci_phys_spec) / sizeof (int));
1936211554Srpaulo	kmem_free(sp, count * sizeof (*sp));
1937211554Srpaulo}
1938211554Srpaulo
1939211554Srpaulostatic void
1940211554Srpauloalloc_res_array(void)
1941211554Srpaulo{
1942211554Srpaulo	static int array_max = 0;
1943211554Srpaulo	int old_max;
1944211554Srpaulo	void *old_res;
1945211554Srpaulo
1946211554Srpaulo	if (array_max > pci_bios_nbus + 1)
1947211554Srpaulo		return;	/* array is big enough */
1948211554Srpaulo
1949178479Sjb	old_max = array_max;
1950178479Sjb	old_res = pci_bus_res;
1951178479Sjb
1952178479Sjb	if (array_max == 0)
1953178479Sjb		array_max = 16;	/* start with a reasonable number */
1954178479Sjb
1955178573Sjb	while (array_max < pci_bios_nbus + 1)
1956178573Sjb		array_max <<= 1;
1957178573Sjb	pci_bus_res = (struct pci_bus_resource *)kmem_zalloc(
1958178573Sjb	    array_max * sizeof (struct pci_bus_resource), KM_SLEEP);
1959178479Sjb
1960178479Sjb	if (old_res) {	/* copy content and free old array */
1961		bcopy(old_res, pci_bus_res,
1962		    old_max * sizeof (struct pci_bus_resource));
1963		kmem_free(old_res, old_max * sizeof (struct pci_bus_resource));
1964	}
1965}
1966
1967static void
1968create_ioapic_node(int bus, int dev, int fn, ushort_t vendorid,
1969    ushort_t deviceid)
1970{
1971	static dev_info_t *ioapicsnode = NULL;
1972	static int numioapics = 0;
1973	dev_info_t *ioapic_node;
1974	uint64_t physaddr;
1975	uint32_t lobase, hibase = 0;
1976
1977	/* BAR 0 contains the IOAPIC's memory-mapped I/O address */
1978	lobase = (*pci_getl_func)(bus, dev, fn, PCI_CONF_BASE0);
1979
1980	/* We (and the rest of the world) only support memory-mapped IOAPICs */
1981	if ((lobase & PCI_BASE_SPACE_M) != PCI_BASE_SPACE_MEM)
1982		return;
1983
1984	if ((lobase & PCI_BASE_TYPE_M) == PCI_BASE_TYPE_ALL)
1985		hibase = (*pci_getl_func)(bus, dev, fn, PCI_CONF_BASE0 + 4);
1986
1987	lobase &= PCI_BASE_M_ADDR_M;
1988
1989	physaddr = (((uint64_t)hibase) << 32) | lobase;
1990
1991	/*
1992	 * Create a nexus node for all IOAPICs under the root node.
1993	 */
1994	if (ioapicsnode == NULL) {
1995		if (ndi_devi_alloc(ddi_root_node(), IOAPICS_NODE_NAME,
1996		    (pnode_t)DEVI_SID_NODEID, &ioapicsnode) != NDI_SUCCESS) {
1997			return;
1998		}
1999		(void) ndi_devi_online(ioapicsnode, 0);
2000	}
2001
2002	/*
2003	 * Create a child node for this IOAPIC
2004	 */
2005	ioapic_node = ddi_add_child(ioapicsnode, IOAPICS_CHILD_NAME,
2006	    DEVI_SID_NODEID, numioapics++);
2007	if (ioapic_node == NULL) {
2008		return;
2009	}
2010
2011	/* Vendor and Device ID */
2012	(void) ndi_prop_update_int(DDI_DEV_T_NONE, ioapic_node,
2013	    IOAPICS_PROP_VENID, vendorid);
2014	(void) ndi_prop_update_int(DDI_DEV_T_NONE, ioapic_node,
2015	    IOAPICS_PROP_DEVID, deviceid);
2016
2017	/* device_type */
2018	(void) ndi_prop_update_string(DDI_DEV_T_NONE, ioapic_node,
2019	    "device_type", IOAPICS_DEV_TYPE);
2020
2021	/* reg */
2022	(void) ndi_prop_update_int64(DDI_DEV_T_NONE, ioapic_node,
2023	    "reg", physaddr);
2024}
2025