xref: /illumos-gate/usr/src/uts/common/io/pciex/pci_props.c (revision 8c0e49e07bbdf2f210e329cb5044fa436481e710)
1bd97c7ceSRobert Mustacchi /*
2bd97c7ceSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3bd97c7ceSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4bd97c7ceSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5bd97c7ceSRobert Mustacchi  * 1.0 of the CDDL.
6bd97c7ceSRobert Mustacchi  *
7bd97c7ceSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8bd97c7ceSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9bd97c7ceSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10bd97c7ceSRobert Mustacchi  */
11bd97c7ceSRobert Mustacchi 
12bd97c7ceSRobert Mustacchi /*
13*8c0e49e0SRobert Mustacchi  * Copyright 2024 Oxide Computer company
14bd97c7ceSRobert Mustacchi  */
15bd97c7ceSRobert Mustacchi 
16bd97c7ceSRobert Mustacchi /*
17bd97c7ceSRobert Mustacchi  * This file consolidates the basic devinfo properties that exist in the system
18bd97c7ceSRobert Mustacchi  * for PCI and PCI Express devices and attempts to ensure that there is only one
19bd97c7ceSRobert Mustacchi  * place to set these items. There are a bunch of different historical
20bd97c7ceSRobert Mustacchi  * considerations that are taken into account here.
21bd97c7ceSRobert Mustacchi  *
22bd97c7ceSRobert Mustacchi  * PCI Compatible Aliases
23bd97c7ceSRobert Mustacchi  * ----------------------
24bd97c7ceSRobert Mustacchi  *
25bd97c7ceSRobert Mustacchi  * The set of aliases that we put on devices is used in the 'compatible'
26bd97c7ceSRobert Mustacchi  * property to attach device drivers to nodes. These are ordered from more
27bd97c7ceSRobert Mustacchi  * specific aliases to less specific aliases. The original set of aliases that
28bd97c7ceSRobert Mustacchi  * was used was defined by Open Firmware for PCI and discussed in the PCI and
29bd97c7ceSRobert Mustacchi  * later the PCI Express bindings as part of IEEE 1275. Originally those
30bd97c7ceSRobert Mustacchi  * bindings consisted of aliases which we could describe as:
31bd97c7ceSRobert Mustacchi  *
32bd97c7ceSRobert Mustacchi  * pci<vendor id>,<device id>.<subsystem vendor>.<subsytem id>.<revision>
33bd97c7ceSRobert Mustacchi  * pci<vendor id>,<device id>.<subsystem vendor>.<subsytem id>
34bd97c7ceSRobert Mustacchi  * pci<subsystem vendor>,<subsytem id>
35bd97c7ceSRobert Mustacchi  * pci<vendor id>,<device id>.<revision>
36bd97c7ceSRobert Mustacchi  * pci<vendor id>,<device id>
37bd97c7ceSRobert Mustacchi  * pciclass,<class code><subclass><programming interface>
38bd97c7ceSRobert Mustacchi  * pciclass,<class code><subclass>
39bd97c7ceSRobert Mustacchi  *
40bd97c7ceSRobert Mustacchi  * When it came time to move to PCI Express, Sun had published a draft document
41bd97c7ceSRobert Mustacchi  * for how to adopt IEEE 1275 bindings to PCI Express. Most notably it dropped
42bd97c7ceSRobert Mustacchi  * the pci<subsystem vendor>.<subsytem id> entry and instead prefixed everything
43bd97c7ceSRobert Mustacchi  * with 'pciex' instead of 'pci'. The reason that this was dropped was because
44bd97c7ceSRobert Mustacchi  * of the fact that while the early days assumed that subsystem IDs were in a
45bd97c7ceSRobert Mustacchi  * shared namespace with device IDs, they ended up overlapping and therefore
46bd97c7ceSRobert Mustacchi  * have not proven to be unique. Because that ID syntax overlapped with
47bd97c7ceSRobert Mustacchi  * pci<vendor id>,<device id> this has led to problems where IDs are reused and
48bd97c7ceSRobert Mustacchi  * incorrect bindings occur. We already maintain a deny list where there are
49bd97c7ceSRobert Mustacchi  * known conflicts.
50bd97c7ceSRobert Mustacchi  *
51bd97c7ceSRobert Mustacchi  * To deal with the ambiguity here while trying to avoid the challenges of the
52bd97c7ceSRobert Mustacchi  * figuring out what IDs were meant to be subsystem IDs and which were primary
53bd97c7ceSRobert Mustacchi  * IDs (a non-obvious task given that some device drivers are almost exclusively
54bd97c7ceSRobert Mustacchi  * identified by standalone subsystem IDs -- see smrt(4D) and cpqary3(4D)), we
55bd97c7ceSRobert Mustacchi  * added two additional aliases for PCI (but not PCI Express) that allow drivers
56bd97c7ceSRobert Mustacchi  * to express what we call disambiguated IDs. These take the form:
57bd97c7ceSRobert Mustacchi  *
58bd97c7ceSRobert Mustacchi  * pci<subsystem vendor>,<subsystem id>,s
59bd97c7ceSRobert Mustacchi  * pci<vendor id>,<device id>,p
60bd97c7ceSRobert Mustacchi  *
61bd97c7ceSRobert Mustacchi  * Were that this was our only challenge. The next bit that we have to deal with
62bd97c7ceSRobert Mustacchi  * is another artifact of history. While Sun proposed the different PCIe
63bd97c7ceSRobert Mustacchi  * bindings in a draft, the original intent was just that the aliases would all
64bd97c7ceSRobert Mustacchi  * take the form of 'pciex' as above and that was it. However, the x86
65bd97c7ceSRobert Mustacchi  * implementation didn't actually roll with the plan. Instead, it placed the set
66bd97c7ceSRobert Mustacchi  * of PCI Express aliases and then followed it with the traditional PCI aliases.
67bd97c7ceSRobert Mustacchi  * As such, they have double the aliases. We still maintain this on x86, but do
68bd97c7ceSRobert Mustacchi  * not extend the double aliases to other platforms. Because these are specific
69bd97c7ceSRobert Mustacchi  * to the platform and not the instruction set architecture, whether this is
70bd97c7ceSRobert Mustacchi  * required or not is indicated by the PCI PRD compat flags interface
71bd97c7ceSRobert Mustacchi  * pci_prd_compat_flags().
72bd97c7ceSRobert Mustacchi  *
73bd97c7ceSRobert Mustacchi  * The last current wrinkle here is that of bridge IDs. Originally PCI bridges
74bd97c7ceSRobert Mustacchi  * didn't have any form of subsystem ID defined. In the PCI-PCI bridge
75bd97c7ceSRobert Mustacchi  * specification version 1.2, published in 2003, they eventually added an
76bd97c7ceSRobert Mustacchi  * optional capability to define a bridge's subsystem. This meant that for most
77bd97c7ceSRobert Mustacchi  * of PCI's existence this did not exist. In particular, until 2023 we did not
78bd97c7ceSRobert Mustacchi  * try to search for the capability and add it to a device's compatible
79bd97c7ceSRobert Mustacchi  * properties. Because of this lapse and having to deal with the above ID
80bd97c7ceSRobert Mustacchi  * disambiguation, we only add the disambiguated ,s subsystem ID for PCI. Both
81bd97c7ceSRobert Mustacchi  * PCI Express and PCI still have the fully qualified subsystem IDs added for
82bd97c7ceSRobert Mustacchi  * bridges.
83bd97c7ceSRobert Mustacchi  *
84bd97c7ceSRobert Mustacchi  * Our final set of aliases that we assign to all nodes is in the table below
85bd97c7ceSRobert Mustacchi  * called 'pci_alias_table'. This table has flags which control the behavior of
86bd97c7ceSRobert Mustacchi  * the ID generation. To summarize what a platform can control is:
87bd97c7ceSRobert Mustacchi  *
88bd97c7ceSRobert Mustacchi  *   o Whether or not both PCIe and PCI aliases are generated. This is
89bd97c7ceSRobert Mustacchi  *     controlled via PCI_PRD_COMPAT_PCI_NODE_NAME which also influences the
90bd97c7ceSRobert Mustacchi  *     node name below.
91bd97c7ceSRobert Mustacchi  *   o For PCI, whether or not we should generate the ambiguous subsystem ID
92bd97c7ceSRobert Mustacchi  *     alias. This is controlled by PCI_PRD_COMPAT_SUBSYS. We will always
93bd97c7ceSRobert Mustacchi  *     generate the disambiguated IDs for PCI to stick with IEEE 1275
94bd97c7ceSRobert Mustacchi  *     expectations across the system. PCI Express will not generate either of
95bd97c7ceSRobert Mustacchi  *     the standalone subsystem ID forms.
96bd97c7ceSRobert Mustacchi  *
97bd97c7ceSRobert Mustacchi  * Node Naming
98bd97c7ceSRobert Mustacchi  * -----------
99bd97c7ceSRobert Mustacchi  *
100bd97c7ceSRobert Mustacchi  * When we name devinfo names we generally do so in the form <type><subsystem
101bd97c7ceSRobert Mustacchi  * vendor id>,<subsystem id>. If there is no subsystem ID then we use
102bd97c7ceSRobert Mustacchi  * <type><vendor id>,<device id>. Type 1 headers do not have a subsystem ID.
103bd97c7ceSRobert Mustacchi  * They are instead found in an optional capability. Type 0 headers do have a
104bd97c7ceSRobert Mustacchi  * subsystem ID. If the subsystem vendor ID is zero, that indicates that the
105bd97c7ceSRobert Mustacchi  * subsystem ID is not present and we fall back to the vendor and device ID.
106bd97c7ceSRobert Mustacchi  *
107bd97c7ceSRobert Mustacchi  * x86 is again a land of exceptions. Because we never had subsystem IDs present
108bd97c7ceSRobert Mustacchi  * for bridges, they always use the vendor and device variant for compatibility
109bd97c7ceSRobert Mustacchi  * purposes. Similarly, x86 always sets the type to "pci" for compatibility.
110bd97c7ceSRobert Mustacchi  * Other platforms will set the type to "pciex" if it is a PCI Express device or
111bd97c7ceSRobert Mustacchi  * "pci" otherwise.
112bd97c7ceSRobert Mustacchi  *
113bd97c7ceSRobert Mustacchi  * Traditionally, node naming was originally driven by the PROM on SPARC which
114bd97c7ceSRobert Mustacchi  * used IEEE 1275 Open Firmware device class names instead of just the device
115bd97c7ceSRobert Mustacchi  * IDs that we have settled on. On our platforms there are two exceptions to
116bd97c7ceSRobert Mustacchi  * this. If we find an ISA compatible system and the PCI PRD indicates that the
117bd97c7ceSRobert Mustacchi  * platform supports ISA, then we will override that. In addition, a subset of
118bd97c7ceSRobert Mustacchi  * the display class codes have historically been used to name a device node
119bd97c7ceSRobert Mustacchi  * "display".
120bd97c7ceSRobert Mustacchi  *
121bd97c7ceSRobert Mustacchi  * Our order for naming device nodes is:
122bd97c7ceSRobert Mustacchi  *
123bd97c7ceSRobert Mustacchi  * 1. Check for display.
124bd97c7ceSRobert Mustacchi  * 2. Check for ISA.
125bd97c7ceSRobert Mustacchi  * 3. Attempt to use the subsystem.
126bd97c7ceSRobert Mustacchi  * 4. Fall back to the normal vendor and device.
127bd97c7ceSRobert Mustacchi  *
128bd97c7ceSRobert Mustacchi  * Platforms can influence this in the following ways:
129bd97c7ceSRobert Mustacchi  *
130bd97c7ceSRobert Mustacchi  *   o ISA is only considered if PCI_PRD_COMPAT_ISA is set.
131bd97c7ceSRobert Mustacchi  *   o Bridges will not use the subsystem IDs if PCI_PRD_COMPAT_SUBSYS is set.
132bd97c7ceSRobert Mustacchi  *   o The node name will always start with "pci" if
133bd97c7ceSRobert Mustacchi  *     PCI_PRD_COMPAT_PCI_NODE_NAME is set.
134bd97c7ceSRobert Mustacchi  *
135bd97c7ceSRobert Mustacchi  * Unit Address
136bd97c7ceSRobert Mustacchi  * ------------
137bd97c7ceSRobert Mustacchi  *
138bd97c7ceSRobert Mustacchi  * The unit address for a PCI device has historically been its device number.
139bd97c7ceSRobert Mustacchi  * For multi-function devices, everything past function zero is the device
140bd97c7ceSRobert Mustacchi  * number followed by the function number. ARI devices technically don't have a
141bd97c7ceSRobert Mustacchi  * device number. If we encounter such a device, we just set the device portion
142bd97c7ceSRobert Mustacchi  * of the unit address to 0.
143bd97c7ceSRobert Mustacchi  */
144bd97c7ceSRobert Mustacchi 
145bd97c7ceSRobert Mustacchi #include <sys/ddi.h>
146bd97c7ceSRobert Mustacchi #include <sys/sunddi.h>
147bd97c7ceSRobert Mustacchi #include <sys/sunndi.h>
148bd97c7ceSRobert Mustacchi #include <sys/cmn_err.h>
149bd97c7ceSRobert Mustacchi #include <sys/pci.h>
150bd97c7ceSRobert Mustacchi #include <sys/pcie.h>
151bd97c7ceSRobert Mustacchi #include <sys/pci_cfgspace.h>
152bd97c7ceSRobert Mustacchi #include <sys/pci_props.h>
153bd97c7ceSRobert Mustacchi #include <sys/sysmacros.h>
154bd97c7ceSRobert Mustacchi #include <sys/plat/pci_prd.h>
155bd97c7ceSRobert Mustacchi #include <pci_strings.h>
156bd97c7ceSRobert Mustacchi 
157bd97c7ceSRobert Mustacchi typedef struct {
158bd97c7ceSRobert Mustacchi 	uint8_t ppc_class;
159bd97c7ceSRobert Mustacchi 	uint8_t ppc_subclass;
160bd97c7ceSRobert Mustacchi 	uint8_t ppc_pi;
161bd97c7ceSRobert Mustacchi } pci_prop_class_t;
162bd97c7ceSRobert Mustacchi 
163bd97c7ceSRobert Mustacchi static boolean_t
pci_prop_class_match(const pci_prop_data_t * prop,const pci_prop_class_t * class,const size_t nclass,boolean_t check_pi)164bd97c7ceSRobert Mustacchi pci_prop_class_match(const pci_prop_data_t *prop, const pci_prop_class_t *class,
165bd97c7ceSRobert Mustacchi     const size_t nclass, boolean_t check_pi)
166bd97c7ceSRobert Mustacchi {
167bd97c7ceSRobert Mustacchi 	for (size_t i = 0; i < nclass; i++) {
168bd97c7ceSRobert Mustacchi 		if (prop->ppd_class == class[i].ppc_class &&
169bd97c7ceSRobert Mustacchi 		    prop->ppd_subclass == class[i].ppc_subclass &&
170bd97c7ceSRobert Mustacchi 		    (!check_pi || prop->ppd_pi == class[i].ppc_pi)) {
171bd97c7ceSRobert Mustacchi 			return (B_TRUE);
172bd97c7ceSRobert Mustacchi 		}
173bd97c7ceSRobert Mustacchi 	}
174bd97c7ceSRobert Mustacchi 
175bd97c7ceSRobert Mustacchi 	return (B_FALSE);
176bd97c7ceSRobert Mustacchi }
177bd97c7ceSRobert Mustacchi 
178bd97c7ceSRobert Mustacchi /*
179bd97c7ceSRobert Mustacchi  * This is used to determine if a given set of data indicates that we have
180bd97c7ceSRobert Mustacchi  * encountered a VGA class code which should be given the "display" name. The
181bd97c7ceSRobert Mustacchi  * following tuples of class, subclass, programming interface are VGA
182bd97c7ceSRobert Mustacchi  * compatible:
183bd97c7ceSRobert Mustacchi  *
184bd97c7ceSRobert Mustacchi  * 0x00, 0x01, 0x00: The pre-class code VGA device
185bd97c7ceSRobert Mustacchi  * 0x03, 0x00, 0x00: A VGA Compatible controller
186bd97c7ceSRobert Mustacchi  * 0x03, 0x00, 0x01: A 8514 compatible controller
187bd97c7ceSRobert Mustacchi  */
188bd97c7ceSRobert Mustacchi static const pci_prop_class_t pci_prop_vga_classes[] = {
189bd97c7ceSRobert Mustacchi 	{ PCI_CLASS_NONE, PCI_NONE_VGA, 0x00 },
190bd97c7ceSRobert Mustacchi 	{ PCI_CLASS_DISPLAY, PCI_DISPLAY_VGA, PCI_DISPLAY_IF_VGA },
191bd97c7ceSRobert Mustacchi 	{ PCI_CLASS_DISPLAY, PCI_DISPLAY_VGA, PCI_DISPLAY_IF_8514 }
192bd97c7ceSRobert Mustacchi };
193bd97c7ceSRobert Mustacchi 
194bd97c7ceSRobert Mustacchi static const pci_prop_class_t pci_prop_ioapic_classes[] = {
195bd97c7ceSRobert Mustacchi 	{ PCI_CLASS_PERIPH, PCI_PERIPH_PIC, PCI_PERIPH_PIC_IF_IO_APIC },
196bd97c7ceSRobert Mustacchi 	{ PCI_CLASS_PERIPH, PCI_PERIPH_PIC, PCI_PERIPH_PIC_IF_IOX_APIC },
197bd97c7ceSRobert Mustacchi };
198bd97c7ceSRobert Mustacchi 
199bd97c7ceSRobert Mustacchi static const pci_prop_class_t pci_prop_isa_classes[] = {
200bd97c7ceSRobert Mustacchi 	{ PCI_CLASS_BRIDGE, PCI_BRIDGE_ISA, 0 }
201bd97c7ceSRobert Mustacchi };
202bd97c7ceSRobert Mustacchi 
203bd97c7ceSRobert Mustacchi static const pci_prop_class_t pci_prop_pcibridge_classes[] = {
204bd97c7ceSRobert Mustacchi 	{ PCI_CLASS_BRIDGE, PCI_BRIDGE_PCI, 0 }
205bd97c7ceSRobert Mustacchi };
206bd97c7ceSRobert Mustacchi 
207bd97c7ceSRobert Mustacchi boolean_t
pci_prop_class_is_vga(const pci_prop_data_t * prop)208bd97c7ceSRobert Mustacchi pci_prop_class_is_vga(const pci_prop_data_t *prop)
209bd97c7ceSRobert Mustacchi {
210bd97c7ceSRobert Mustacchi 	return (pci_prop_class_match(prop, pci_prop_vga_classes,
211bd97c7ceSRobert Mustacchi 	    ARRAY_SIZE(pci_prop_vga_classes), B_TRUE));
212bd97c7ceSRobert Mustacchi }
213bd97c7ceSRobert Mustacchi 
214bd97c7ceSRobert Mustacchi boolean_t
pci_prop_class_is_ioapic(const pci_prop_data_t * prop)215bd97c7ceSRobert Mustacchi pci_prop_class_is_ioapic(const pci_prop_data_t *prop)
216bd97c7ceSRobert Mustacchi {
217bd97c7ceSRobert Mustacchi 	return (pci_prop_class_match(prop, pci_prop_ioapic_classes,
218bd97c7ceSRobert Mustacchi 	    ARRAY_SIZE(pci_prop_ioapic_classes), B_TRUE));
219bd97c7ceSRobert Mustacchi }
220bd97c7ceSRobert Mustacchi 
221bd97c7ceSRobert Mustacchi /*
222bd97c7ceSRobert Mustacchi  * Determine if a class indicates that it is ISA. Technically this should be
223bd97c7ceSRobert Mustacchi  * checking the programming interface as only PI 0x00 is defined; however, this
224bd97c7ceSRobert Mustacchi  * is the check that has historically been done and the PCI-SIG is unlikely to
225bd97c7ceSRobert Mustacchi  * define additional programming interfaces for an ISA bridge.
226bd97c7ceSRobert Mustacchi  */
227bd97c7ceSRobert Mustacchi boolean_t
pci_prop_class_is_isa(const pci_prop_data_t * prop)228bd97c7ceSRobert Mustacchi pci_prop_class_is_isa(const pci_prop_data_t *prop)
229bd97c7ceSRobert Mustacchi {
230bd97c7ceSRobert Mustacchi 	return (pci_prop_class_match(prop, pci_prop_isa_classes,
231bd97c7ceSRobert Mustacchi 	    ARRAY_SIZE(pci_prop_isa_classes), B_FALSE));
232bd97c7ceSRobert Mustacchi }
233bd97c7ceSRobert Mustacchi 
234bd97c7ceSRobert Mustacchi /*
235bd97c7ceSRobert Mustacchi  * We don't check the programming class here because callers don't care if this
236bd97c7ceSRobert Mustacchi  * is subtractive or not.
237bd97c7ceSRobert Mustacchi  */
238bd97c7ceSRobert Mustacchi boolean_t
pci_prop_class_is_pcibridge(const pci_prop_data_t * prop)239bd97c7ceSRobert Mustacchi pci_prop_class_is_pcibridge(const pci_prop_data_t *prop)
240bd97c7ceSRobert Mustacchi {
241bd97c7ceSRobert Mustacchi 	return (pci_prop_class_match(prop, pci_prop_pcibridge_classes,
242bd97c7ceSRobert Mustacchi 	    ARRAY_SIZE(pci_prop_pcibridge_classes), B_FALSE));
243bd97c7ceSRobert Mustacchi }
244bd97c7ceSRobert Mustacchi 
245bd97c7ceSRobert Mustacchi static const char *
pci_prop_nodename_prefix(const pci_prop_data_t * prop,pci_prd_compat_flags_t flags)246bd97c7ceSRobert Mustacchi pci_prop_nodename_prefix(const pci_prop_data_t *prop,
247bd97c7ceSRobert Mustacchi     pci_prd_compat_flags_t flags)
248bd97c7ceSRobert Mustacchi {
249bd97c7ceSRobert Mustacchi 	if ((flags & PCI_PRD_COMPAT_PCI_NODE_NAME) != 0) {
250bd97c7ceSRobert Mustacchi 		return ("pci");
251bd97c7ceSRobert Mustacchi 	}
252bd97c7ceSRobert Mustacchi 
253bd97c7ceSRobert Mustacchi 	if ((prop->ppd_flags & PCI_PROP_F_PCIE) != 0) {
254bd97c7ceSRobert Mustacchi 		return ("pciex");
255bd97c7ceSRobert Mustacchi 	} else {
256bd97c7ceSRobert Mustacchi 		return ("pci");
257bd97c7ceSRobert Mustacchi 	}
258bd97c7ceSRobert Mustacchi }
259bd97c7ceSRobert Mustacchi 
260bd97c7ceSRobert Mustacchi static boolean_t
pci_prop_use_subsystem(const pci_prop_data_t * prop,pci_prd_compat_flags_t flags)261bd97c7ceSRobert Mustacchi pci_prop_use_subsystem(const pci_prop_data_t *prop,
262bd97c7ceSRobert Mustacchi     pci_prd_compat_flags_t flags)
263bd97c7ceSRobert Mustacchi {
264bd97c7ceSRobert Mustacchi 	if ((flags & PCI_PRD_COMPAT_SUBSYS) != 0 &&
265bd97c7ceSRobert Mustacchi 	    prop->ppd_header == PCI_HEADER_PPB) {
266bd97c7ceSRobert Mustacchi 		return (B_FALSE);
267bd97c7ceSRobert Mustacchi 	}
268bd97c7ceSRobert Mustacchi 
269bd97c7ceSRobert Mustacchi 	return (prop->ppd_subvid != 0);
270bd97c7ceSRobert Mustacchi }
271bd97c7ceSRobert Mustacchi 
272bd97c7ceSRobert Mustacchi /*
273bd97c7ceSRobert Mustacchi  * Name a device node per the theory statement.
274bd97c7ceSRobert Mustacchi  */
275bd97c7ceSRobert Mustacchi pci_prop_failure_t
pci_prop_name_node(dev_info_t * dip,const pci_prop_data_t * prop)276bd97c7ceSRobert Mustacchi pci_prop_name_node(dev_info_t *dip, const pci_prop_data_t *prop)
277bd97c7ceSRobert Mustacchi {
278bd97c7ceSRobert Mustacchi 	char buf[64];
279bd97c7ceSRobert Mustacchi 	pci_prd_compat_flags_t flags = pci_prd_compat_flags();
280bd97c7ceSRobert Mustacchi 
281bd97c7ceSRobert Mustacchi 	if (pci_prop_class_is_vga(prop)) {
282bd97c7ceSRobert Mustacchi 		(void) snprintf(buf, sizeof (buf), "display");
283bd97c7ceSRobert Mustacchi 	} else if (pci_prop_class_is_isa(prop) &&
284bd97c7ceSRobert Mustacchi 	    (flags & PCI_PRD_COMPAT_ISA) != 0) {
285bd97c7ceSRobert Mustacchi 		(void) snprintf(buf, sizeof (buf), "isa");
286bd97c7ceSRobert Mustacchi 	} else {
287bd97c7ceSRobert Mustacchi 		const char *prefix = pci_prop_nodename_prefix(prop, flags);
288bd97c7ceSRobert Mustacchi 
289bd97c7ceSRobert Mustacchi 		if (pci_prop_use_subsystem(prop, flags)) {
290bd97c7ceSRobert Mustacchi 			(void) snprintf(buf, sizeof (buf), "%s%x,%x", prefix,
291bd97c7ceSRobert Mustacchi 			    prop->ppd_subvid, prop->ppd_subsys);
292bd97c7ceSRobert Mustacchi 		} else {
293bd97c7ceSRobert Mustacchi 			(void) snprintf(buf, sizeof (buf), "%s%x,%x", prefix,
294bd97c7ceSRobert Mustacchi 			    prop->ppd_vendid, prop->ppd_devid);
295bd97c7ceSRobert Mustacchi 		}
296bd97c7ceSRobert Mustacchi 	}
297bd97c7ceSRobert Mustacchi 
298bd97c7ceSRobert Mustacchi 	if (ndi_devi_set_nodename(dip, buf, 0) != NDI_SUCCESS) {
299bd97c7ceSRobert Mustacchi 		return (PCI_PROP_E_NDI);
300bd97c7ceSRobert Mustacchi 	}
301bd97c7ceSRobert Mustacchi 	return (PCI_PROP_OK);
302bd97c7ceSRobert Mustacchi }
303bd97c7ceSRobert Mustacchi 
304bd97c7ceSRobert Mustacchi static uint8_t
pci_prop_get8(ddi_acc_handle_t acc,const pci_prop_data_t * prop,uint16_t off)305bd97c7ceSRobert Mustacchi pci_prop_get8(ddi_acc_handle_t acc, const pci_prop_data_t *prop, uint16_t off)
306bd97c7ceSRobert Mustacchi {
307bd97c7ceSRobert Mustacchi 	if (acc == NULL) {
308bd97c7ceSRobert Mustacchi 		return ((*pci_getb_func)(prop->ppd_bus, prop->ppd_dev,
309bd97c7ceSRobert Mustacchi 		    prop->ppd_func, off));
310bd97c7ceSRobert Mustacchi 	} else {
311bd97c7ceSRobert Mustacchi 		return (pci_config_get8(acc, off));
312bd97c7ceSRobert Mustacchi 	}
313bd97c7ceSRobert Mustacchi }
314bd97c7ceSRobert Mustacchi 
315bd97c7ceSRobert Mustacchi static uint16_t
pci_prop_get16(ddi_acc_handle_t acc,const pci_prop_data_t * prop,uint16_t off)316bd97c7ceSRobert Mustacchi pci_prop_get16(ddi_acc_handle_t acc, const pci_prop_data_t *prop, uint16_t off)
317bd97c7ceSRobert Mustacchi {
318bd97c7ceSRobert Mustacchi 	if (acc == NULL) {
319bd97c7ceSRobert Mustacchi 		return ((*pci_getw_func)(prop->ppd_bus, prop->ppd_dev,
320bd97c7ceSRobert Mustacchi 		    prop->ppd_func, off));
321bd97c7ceSRobert Mustacchi 	} else {
322bd97c7ceSRobert Mustacchi 		return (pci_config_get16(acc, off));
323bd97c7ceSRobert Mustacchi 	}
324bd97c7ceSRobert Mustacchi }
325bd97c7ceSRobert Mustacchi 
326bd97c7ceSRobert Mustacchi static uint32_t
pci_prop_get32(ddi_acc_handle_t acc,const pci_prop_data_t * prop,uint16_t off)327bd97c7ceSRobert Mustacchi pci_prop_get32(ddi_acc_handle_t acc, const pci_prop_data_t *prop, uint16_t off)
328bd97c7ceSRobert Mustacchi {
329bd97c7ceSRobert Mustacchi 	if (acc == NULL) {
330bd97c7ceSRobert Mustacchi 		return ((*pci_getl_func)(prop->ppd_bus, prop->ppd_dev,
331bd97c7ceSRobert Mustacchi 		    prop->ppd_func, off));
332bd97c7ceSRobert Mustacchi 	} else {
333bd97c7ceSRobert Mustacchi 		return (pci_config_get32(acc, off));
334bd97c7ceSRobert Mustacchi 	}
335bd97c7ceSRobert Mustacchi }
336bd97c7ceSRobert Mustacchi 
337bd97c7ceSRobert Mustacchi static pci_prop_failure_t
pci_prop_data_fill_pcie(ddi_acc_handle_t acc,pci_prop_data_t * prop,uint8_t cap_base)338bd97c7ceSRobert Mustacchi pci_prop_data_fill_pcie(ddi_acc_handle_t acc, pci_prop_data_t *prop,
339bd97c7ceSRobert Mustacchi     uint8_t cap_base)
340bd97c7ceSRobert Mustacchi {
341bd97c7ceSRobert Mustacchi 	uint16_t pciecap;
342bd97c7ceSRobert Mustacchi 	uint32_t slotcap;
343bd97c7ceSRobert Mustacchi 	uint8_t vers;
344bd97c7ceSRobert Mustacchi 
345bd97c7ceSRobert Mustacchi 	pciecap = pci_prop_get16(acc, prop, cap_base + PCIE_PCIECAP);
346bd97c7ceSRobert Mustacchi 	vers = pciecap & PCIE_PCIECAP_VER_MASK;
347bd97c7ceSRobert Mustacchi 	switch (vers) {
348bd97c7ceSRobert Mustacchi 	case PCIE_PCIECAP_VER_1_0:
349bd97c7ceSRobert Mustacchi 	case PCIE_PCIECAP_VER_2_0:
350bd97c7ceSRobert Mustacchi 		break;
351bd97c7ceSRobert Mustacchi 	default:
352bd97c7ceSRobert Mustacchi 		cmn_err(CE_WARN, "found device at b/d/f 0x%x/0x%x/0x%x with "
353bd97c7ceSRobert Mustacchi 		    "PCIe capability with unsupported capability version: 0x%x",
354bd97c7ceSRobert Mustacchi 		    prop->ppd_bus, prop->ppd_dev, prop->ppd_func, vers);
355bd97c7ceSRobert Mustacchi 		return (PCI_PROP_E_BAD_PCIE_CAP);
356bd97c7ceSRobert Mustacchi 	}
357bd97c7ceSRobert Mustacchi 
358bd97c7ceSRobert Mustacchi 	prop->ppd_flags |= PCI_PROP_F_PCIE;
359bd97c7ceSRobert Mustacchi 	prop->ppd_pcie_type = pciecap & PCIE_PCIECAP_DEV_TYPE_MASK;
360bd97c7ceSRobert Mustacchi 
361bd97c7ceSRobert Mustacchi 	if ((pciecap & PCIE_PCIECAP_SLOT_IMPL) == 0) {
362bd97c7ceSRobert Mustacchi 		return (PCI_PROP_OK);
363bd97c7ceSRobert Mustacchi 	}
364bd97c7ceSRobert Mustacchi 
365bd97c7ceSRobert Mustacchi 	slotcap = pci_prop_get32(acc, prop, cap_base + PCIE_SLOTCAP);
366bd97c7ceSRobert Mustacchi 	prop->ppd_slotno = PCIE_SLOTCAP_PHY_SLOT_NUM(slotcap);
367bd97c7ceSRobert Mustacchi 	prop->ppd_flags |= PCI_PROP_F_SLOT_VALID;
368bd97c7ceSRobert Mustacchi 	return (PCI_PROP_OK);
369bd97c7ceSRobert Mustacchi }
370bd97c7ceSRobert Mustacchi 
371bd97c7ceSRobert Mustacchi /*
372bd97c7ceSRobert Mustacchi  * Obtain basic information about a device and store it for future processing
373bd97c7ceSRobert Mustacchi  * and for other code's general usage. This may be called early in boot before
374bd97c7ceSRobert Mustacchi  * we feel like we should use the normal access routines or later in boot where
375bd97c7ceSRobert Mustacchi  * the system opts to use normal DDI accesses. We accept either and make do with
376bd97c7ceSRobert Mustacchi  * the rest.
377bd97c7ceSRobert Mustacchi  *
378bd97c7ceSRobert Mustacchi  * We err on the side of trying to be lenient with devices that are potentially
379bd97c7ceSRobert Mustacchi  * a bit odd. Not all devices in the wild actually follow the spec.
380bd97c7ceSRobert Mustacchi  */
381bd97c7ceSRobert Mustacchi pci_prop_failure_t
pci_prop_data_fill(ddi_acc_handle_t acc,uint8_t bus,uint8_t dev,uint8_t func,pci_prop_data_t * prop)382bd97c7ceSRobert Mustacchi pci_prop_data_fill(ddi_acc_handle_t acc, uint8_t bus, uint8_t dev, uint8_t func,
383bd97c7ceSRobert Mustacchi     pci_prop_data_t *prop)
384bd97c7ceSRobert Mustacchi {
385bd97c7ceSRobert Mustacchi 	uint8_t htype, cap_off, max_cap = PCI_CAP_MAX_PTR;
386bd97c7ceSRobert Mustacchi 	uint16_t status;
387bd97c7ceSRobert Mustacchi 
388bd97c7ceSRobert Mustacchi 	bzero(prop, sizeof (pci_prop_data_t));
389bd97c7ceSRobert Mustacchi 	prop->ppd_bus = bus;
390bd97c7ceSRobert Mustacchi 	prop->ppd_dev = dev;
391bd97c7ceSRobert Mustacchi 	prop->ppd_func = func;
392bd97c7ceSRobert Mustacchi 
393bd97c7ceSRobert Mustacchi 	/*
394bd97c7ceSRobert Mustacchi 	 * To fill this out, begin with getting things that are always going to
395bd97c7ceSRobert Mustacchi 	 * be the same between different header types. We check the validity of
396bd97c7ceSRobert Mustacchi 	 * the vendor ID as a proxy for hardware being present.
397bd97c7ceSRobert Mustacchi 	 */
398bd97c7ceSRobert Mustacchi 	prop->ppd_vendid = pci_prop_get16(acc, prop, PCI_CONF_VENID);
399bd97c7ceSRobert Mustacchi 	if (prop->ppd_vendid == PCI_EINVAL16) {
400bd97c7ceSRobert Mustacchi 		return (PCI_PROP_E_BAD_READ);
401bd97c7ceSRobert Mustacchi 	}
402bd97c7ceSRobert Mustacchi 	prop->ppd_devid = pci_prop_get16(acc, prop, PCI_CONF_DEVID);
403bd97c7ceSRobert Mustacchi 	prop->ppd_rev = pci_prop_get8(acc, prop, PCI_CONF_REVID);
404bd97c7ceSRobert Mustacchi 	prop->ppd_class = pci_prop_get8(acc, prop, PCI_CONF_BASCLASS);
405bd97c7ceSRobert Mustacchi 	prop->ppd_subclass = pci_prop_get8(acc, prop, PCI_CONF_SUBCLASS);
406bd97c7ceSRobert Mustacchi 	prop->ppd_pi = pci_prop_get8(acc, prop, PCI_CONF_PROGCLASS);
407bd97c7ceSRobert Mustacchi 
408bd97c7ceSRobert Mustacchi 	htype = pci_prop_get8(acc, prop, PCI_CONF_HEADER);
409bd97c7ceSRobert Mustacchi 	prop->ppd_header = htype & PCI_HEADER_TYPE_M;
410bd97c7ceSRobert Mustacchi 	if ((htype & PCI_HEADER_MULTI) != 0) {
411bd97c7ceSRobert Mustacchi 		prop->ppd_flags |= PCI_PROP_F_MULT_FUNC;
412bd97c7ceSRobert Mustacchi 	}
413bd97c7ceSRobert Mustacchi 
414bd97c7ceSRobert Mustacchi 
415bd97c7ceSRobert Mustacchi 	/*
416bd97c7ceSRobert Mustacchi 	 * Next, we get fields from the header that vary between device types or
417bd97c7ceSRobert Mustacchi 	 * are specific to a given device type. Bridges do not have a subsystem
418bd97c7ceSRobert Mustacchi 	 * ID at this point, instead we will fetch it out when we walk the basic
419bd97c7ceSRobert Mustacchi 	 * capabilities.
420bd97c7ceSRobert Mustacchi 	 */
421bd97c7ceSRobert Mustacchi 	switch (prop->ppd_header) {
422bd97c7ceSRobert Mustacchi 	case PCI_HEADER_ZERO:
423bd97c7ceSRobert Mustacchi 		prop->ppd_subvid = pci_prop_get16(acc, prop,
424bd97c7ceSRobert Mustacchi 		    PCI_CONF_SUBVENID);
425bd97c7ceSRobert Mustacchi 		prop->ppd_subsys =  pci_prop_get16(acc, prop,
426bd97c7ceSRobert Mustacchi 		    PCI_CONF_SUBSYSID);
427bd97c7ceSRobert Mustacchi 		prop->ppd_mingrt = pci_prop_get8(acc, prop, PCI_CONF_MIN_G);
428bd97c7ceSRobert Mustacchi 		prop->ppd_maxlat = pci_prop_get8(acc, prop, PCI_CONF_MAX_L);
429bd97c7ceSRobert Mustacchi 		break;
430bd97c7ceSRobert Mustacchi 	case PCI_HEADER_CARDBUS:
431bd97c7ceSRobert Mustacchi 		prop->ppd_subvid = pci_prop_get16(acc, prop,
432bd97c7ceSRobert Mustacchi 		    PCI_CBUS_SUBVENID);
433bd97c7ceSRobert Mustacchi 		prop->ppd_subsys =  pci_prop_get16(acc, prop,
434bd97c7ceSRobert Mustacchi 		    PCI_CBUS_SUBSYSID);
435bd97c7ceSRobert Mustacchi 		break;
436bd97c7ceSRobert Mustacchi 	case PCI_HEADER_PPB:
437bd97c7ceSRobert Mustacchi 		break;
438bd97c7ceSRobert Mustacchi 	default:
439bd97c7ceSRobert Mustacchi 		return (PCI_PROP_E_UNKNOWN_HEADER);
440bd97c7ceSRobert Mustacchi 	}
441bd97c7ceSRobert Mustacchi 
442bd97c7ceSRobert Mustacchi 	/*
443bd97c7ceSRobert Mustacchi 	 * Capture registers which are used to derive various devinfo
444bd97c7ceSRobert Mustacchi 	 * properties and are shared between all device types.
445bd97c7ceSRobert Mustacchi 	 */
446bd97c7ceSRobert Mustacchi 	prop->ppd_ipin = pci_prop_get8(acc, prop, PCI_CONF_IPIN);
447bd97c7ceSRobert Mustacchi 	prop->ppd_status = pci_prop_get16(acc, prop, PCI_CONF_STAT);
448bd97c7ceSRobert Mustacchi 
449bd97c7ceSRobert Mustacchi 	/*
450bd97c7ceSRobert Mustacchi 	 * If there are no capabilities, there is nothing else for us to do.
451bd97c7ceSRobert Mustacchi 	 */
452bd97c7ceSRobert Mustacchi 	status = pci_prop_get16(acc, prop, PCI_CONF_STAT);
453bd97c7ceSRobert Mustacchi 	if ((status & PCI_STAT_CAP) == 0)
454bd97c7ceSRobert Mustacchi 		return (PCI_PROP_OK);
455bd97c7ceSRobert Mustacchi 
456bd97c7ceSRobert Mustacchi 	cap_off = pci_prop_get8(acc, prop, PCI_CONF_CAP_PTR);
457bd97c7ceSRobert Mustacchi 	for (; max_cap > 0 && cap_off >= PCI_CAP_PTR_OFF; max_cap--) {
458bd97c7ceSRobert Mustacchi 		uint8_t cap_addr = cap_off & PCI_CAP_PTR_MASK;
459bd97c7ceSRobert Mustacchi 		uint8_t cap_id = pci_prop_get8(acc, prop, cap_addr);
460*8c0e49e0SRobert Mustacchi 		uint16_t subvid, subsys;
461bd97c7ceSRobert Mustacchi 		pci_prop_failure_t ret;
462bd97c7ceSRobert Mustacchi 
463bd97c7ceSRobert Mustacchi 		/*
464bd97c7ceSRobert Mustacchi 		 * Look for an invalid read as a proxy for this being in illegal
465bd97c7ceSRobert Mustacchi 		 * capability and that we're done. We don't treat this as fatal
466bd97c7ceSRobert Mustacchi 		 * as some devices will place the caps at weird places.
467bd97c7ceSRobert Mustacchi 		 */
468bd97c7ceSRobert Mustacchi 		if (cap_id == PCI_EINVAL8) {
469bd97c7ceSRobert Mustacchi 			return (PCI_PROP_OK);
470bd97c7ceSRobert Mustacchi 		}
471bd97c7ceSRobert Mustacchi 
472bd97c7ceSRobert Mustacchi 		switch (cap_id) {
473bd97c7ceSRobert Mustacchi 		case PCI_CAP_ID_PCI_E:
474bd97c7ceSRobert Mustacchi 			ret = pci_prop_data_fill_pcie(acc, prop, cap_addr);
475bd97c7ceSRobert Mustacchi 			if (ret != PCI_PROP_OK) {
476bd97c7ceSRobert Mustacchi 				return (ret);
477bd97c7ceSRobert Mustacchi 			}
478bd97c7ceSRobert Mustacchi 			break;
479bd97c7ceSRobert Mustacchi 		case PCI_CAP_ID_P2P_SUBSYS:
480bd97c7ceSRobert Mustacchi 			/*
481bd97c7ceSRobert Mustacchi 			 * This is only legal in a type 1 header configuration
482*8c0e49e0SRobert Mustacchi 			 * space. In practice we've found some root complex
483*8c0e49e0SRobert Mustacchi 			 * event collectors in the wild that have both. Because
484*8c0e49e0SRobert Mustacchi 			 * this must come after the type 0 header, if this
485*8c0e49e0SRobert Mustacchi 			 * differs then we'll say something.
486bd97c7ceSRobert Mustacchi 			 */
487*8c0e49e0SRobert Mustacchi 			subvid = pci_prop_get16(acc, prop, cap_addr +
488*8c0e49e0SRobert Mustacchi 			    PCI_SUBSYSCAP_SUBVID);
489*8c0e49e0SRobert Mustacchi 			subsys = pci_prop_get16(acc, prop, cap_addr +
490*8c0e49e0SRobert Mustacchi 			    PCI_SUBSYSCAP_SUBSYS);
491*8c0e49e0SRobert Mustacchi 			if (prop->ppd_header == PCI_HEADER_PPB) {
492*8c0e49e0SRobert Mustacchi 				prop->ppd_subvid = subvid;
493*8c0e49e0SRobert Mustacchi 				prop->ppd_subsys = subsys;
494*8c0e49e0SRobert Mustacchi 			} else if (subvid != prop->ppd_subvid ||
495*8c0e49e0SRobert Mustacchi 			    subsys != prop->ppd_subsys) {
496bd97c7ceSRobert Mustacchi 				cmn_err(CE_WARN, "found device at b/d/f "
497bd97c7ceSRobert Mustacchi 				    "0x%x/0x%x/0x%x with PCI subsystem "
498*8c0e49e0SRobert Mustacchi 				    "capability, but wrong header type 0x%x "
499*8c0e49e0SRobert Mustacchi 				    "and mismatched subsystems: header "
500*8c0e49e0SRobert Mustacchi 				    "0x%x/0x%x, cap: 0x%x/0x%x, using header "
501*8c0e49e0SRobert Mustacchi 				    "values", bus, dev, func, prop->ppd_header,
502*8c0e49e0SRobert Mustacchi 				    prop->ppd_subvid, prop->ppd_subsys, subvid,
503*8c0e49e0SRobert Mustacchi 				    subsys);
504bd97c7ceSRobert Mustacchi 				break;
505bd97c7ceSRobert Mustacchi 			}
506bd97c7ceSRobert Mustacchi 
507bd97c7ceSRobert Mustacchi 			break;
508bd97c7ceSRobert Mustacchi 		default:
509bd97c7ceSRobert Mustacchi 			break;
510bd97c7ceSRobert Mustacchi 		}
511bd97c7ceSRobert Mustacchi 
512bd97c7ceSRobert Mustacchi 		/*
513bd97c7ceSRobert Mustacchi 		 * Again, we check for invalid capability offsets to try to flag
514bd97c7ceSRobert Mustacchi 		 * the case of an invalid read. If we have a zero representing
515bd97c7ceSRobert Mustacchi 		 * the end of the list, then we'll break out up above.
516bd97c7ceSRobert Mustacchi 		 */
517bd97c7ceSRobert Mustacchi 		cap_off = pci_prop_get8(acc, prop, cap_addr + PCI_CAP_NEXT_PTR);
518bd97c7ceSRobert Mustacchi 		if (cap_off == PCI_EINVAL8) {
519bd97c7ceSRobert Mustacchi 			return (PCI_PROP_OK);
520bd97c7ceSRobert Mustacchi 		}
521bd97c7ceSRobert Mustacchi 	}
522bd97c7ceSRobert Mustacchi 
523bd97c7ceSRobert Mustacchi 	return (PCI_PROP_OK);
524bd97c7ceSRobert Mustacchi }
525bd97c7ceSRobert Mustacchi 
526bd97c7ceSRobert Mustacchi /*
527bd97c7ceSRobert Mustacchi  * The IEEE 1275 slot-names property has a unique construction. It starts off
528bd97c7ceSRobert Mustacchi  * with a uint32_t which is a bitmask of names for each device. Then there is a
529bd97c7ceSRobert Mustacchi  * number of strings ordered based on the bitfield. The NDI doesn't have a great
530bd97c7ceSRobert Mustacchi  * way to represent this combination of types so we are bound by history which
531bd97c7ceSRobert Mustacchi  * says to use an int array. Yes, this is gross.
532bd97c7ceSRobert Mustacchi  *
533bd97c7ceSRobert Mustacchi  * For PCIe this is at least somewhat straightforward. We only ever have one
534bd97c7ceSRobert Mustacchi  * device so our bitfield value is always 0x1. The name we use is also always
535bd97c7ceSRobert Mustacchi  * "pcie<slot>".
536bd97c7ceSRobert Mustacchi  */
537bd97c7ceSRobert Mustacchi static void
pci_prop_set_pciex_slot_name(dev_info_t * dip,uint16_t slotno)538bd97c7ceSRobert Mustacchi pci_prop_set_pciex_slot_name(dev_info_t *dip, uint16_t slotno)
539bd97c7ceSRobert Mustacchi {
540bd97c7ceSRobert Mustacchi 	uint32_t slot[32];
541bd97c7ceSRobert Mustacchi 	size_t len;
542bd97c7ceSRobert Mustacchi 
543bd97c7ceSRobert Mustacchi 	bzero(slot, sizeof (slot));
544bd97c7ceSRobert Mustacchi 	slot[0] = 1;
545bd97c7ceSRobert Mustacchi 
546bd97c7ceSRobert Mustacchi 	/*
547bd97c7ceSRobert Mustacchi 	 * We need to calculate the number of uint32_t's that we used. We round
548bd97c7ceSRobert Mustacchi 	 * up the number of bytes used for the name, convert that to a number of
549bd97c7ceSRobert Mustacchi 	 * uint32_t's and then add one for the bitfield.
550bd97c7ceSRobert Mustacchi 	 */
551bd97c7ceSRobert Mustacchi 	len = snprintf((char *)&slot[1], sizeof (slot) - sizeof (slot[0]),
552bd97c7ceSRobert Mustacchi 	    "pcie%u", slotno) + 1;
553bd97c7ceSRobert Mustacchi 	len = P2ROUNDUP(len, sizeof (uint32_t));
554bd97c7ceSRobert Mustacchi 	len /= sizeof (uint32_t);
555bd97c7ceSRobert Mustacchi 	len += 1;
556bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "slot-names",
557bd97c7ceSRobert Mustacchi 	    (int *)slot, len);
558bd97c7ceSRobert Mustacchi }
559bd97c7ceSRobert Mustacchi 
560bd97c7ceSRobert Mustacchi pci_prop_failure_t
pci_prop_set_common_props(dev_info_t * dip,const pci_prop_data_t * prop)561bd97c7ceSRobert Mustacchi pci_prop_set_common_props(dev_info_t *dip, const pci_prop_data_t *prop)
562bd97c7ceSRobert Mustacchi {
563bd97c7ceSRobert Mustacchi 	int class;
564bd97c7ceSRobert Mustacchi 	char unitaddr[16];
565bd97c7ceSRobert Mustacchi 	pci_prd_compat_flags_t flags = pci_prd_compat_flags();
566bd97c7ceSRobert Mustacchi 
567bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id",
568bd97c7ceSRobert Mustacchi 	    prop->ppd_vendid);
569bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id",
570bd97c7ceSRobert Mustacchi 	    prop->ppd_devid);
571bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "revision-id",
572bd97c7ceSRobert Mustacchi 	    prop->ppd_rev);
573bd97c7ceSRobert Mustacchi 
574bd97c7ceSRobert Mustacchi 	class = (prop->ppd_class << 16) | (prop->ppd_subclass << 8) |
575bd97c7ceSRobert Mustacchi 	    prop->ppd_pi;
576bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "class-code", class);
577bd97c7ceSRobert Mustacchi 
578bd97c7ceSRobert Mustacchi 	if (prop->ppd_subvid != 0) {
579bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
580bd97c7ceSRobert Mustacchi 		    "subsystem-vendor-id", prop->ppd_subvid);
581bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "subsystem-id",
582bd97c7ceSRobert Mustacchi 		    prop->ppd_subsys);
583bd97c7ceSRobert Mustacchi 	}
584bd97c7ceSRobert Mustacchi 
585bd97c7ceSRobert Mustacchi 	if (prop->ppd_func > 0) {
586bd97c7ceSRobert Mustacchi 		(void) snprintf(unitaddr, sizeof (unitaddr), "%x,%x",
587bd97c7ceSRobert Mustacchi 		    prop->ppd_dev, prop->ppd_func);
588bd97c7ceSRobert Mustacchi 	} else {
589bd97c7ceSRobert Mustacchi 		(void) snprintf(unitaddr, sizeof (unitaddr), "%x",
590bd97c7ceSRobert Mustacchi 		    prop->ppd_dev);
591bd97c7ceSRobert Mustacchi 	}
592bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "unit-address",
593bd97c7ceSRobert Mustacchi 	    unitaddr);
594bd97c7ceSRobert Mustacchi 
595bd97c7ceSRobert Mustacchi 	/*
596bd97c7ceSRobert Mustacchi 	 * Set properties specific to the device class (i.e. PCI or PCIe).
597bd97c7ceSRobert Mustacchi 	 * While devsel-speed is meaningless for PCIe, this is still set
598bd97c7ceSRobert Mustacchi 	 * anyways for it to match tradition.
599bd97c7ceSRobert Mustacchi 	 */
600bd97c7ceSRobert Mustacchi 	if ((prop->ppd_flags & PCI_PROP_F_PCIE) == 0) {
601bd97c7ceSRobert Mustacchi 		if ((prop->ppd_status & PCI_STAT_FBBC) != 0) {
602bd97c7ceSRobert Mustacchi 			(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
603bd97c7ceSRobert Mustacchi 			    "fast-back-to-back");
604bd97c7ceSRobert Mustacchi 		}
605bd97c7ceSRobert Mustacchi 
606bd97c7ceSRobert Mustacchi 		if ((prop->ppd_status & PCI_STAT_66MHZ) != 0) {
607bd97c7ceSRobert Mustacchi 			(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
608bd97c7ceSRobert Mustacchi 			    "66mhz-capable");
609bd97c7ceSRobert Mustacchi 		}
610bd97c7ceSRobert Mustacchi 
611bd97c7ceSRobert Mustacchi 		if ((prop->ppd_status & PCI_STAT_UDF) != 0) {
612bd97c7ceSRobert Mustacchi 			(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
613bd97c7ceSRobert Mustacchi 			    "udf-supported");
614bd97c7ceSRobert Mustacchi 		}
615bd97c7ceSRobert Mustacchi 
616bd97c7ceSRobert Mustacchi 		if (prop->ppd_header == PCI_HEADER_ZERO) {
617bd97c7ceSRobert Mustacchi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
618bd97c7ceSRobert Mustacchi 			    "min-grant", prop->ppd_mingrt);
619bd97c7ceSRobert Mustacchi 
620bd97c7ceSRobert Mustacchi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
621bd97c7ceSRobert Mustacchi 			    "max-latency", prop->ppd_maxlat);
622bd97c7ceSRobert Mustacchi 		}
623bd97c7ceSRobert Mustacchi 	} else {
624bd97c7ceSRobert Mustacchi 		if ((prop->ppd_flags & PCI_PROP_F_SLOT_VALID) != 0) {
625bd97c7ceSRobert Mustacchi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
626bd97c7ceSRobert Mustacchi 			    "physical-slot#", prop->ppd_slotno);
627bd97c7ceSRobert Mustacchi 			if (prop->ppd_pcie_type !=
628bd97c7ceSRobert Mustacchi 			    PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
629bd97c7ceSRobert Mustacchi 				pci_prop_set_pciex_slot_name(dip,
630bd97c7ceSRobert Mustacchi 				    prop->ppd_slotno);
631bd97c7ceSRobert Mustacchi 			}
632bd97c7ceSRobert Mustacchi 		}
633bd97c7ceSRobert Mustacchi 	}
634bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "devsel-speed",
635bd97c7ceSRobert Mustacchi 	    (prop->ppd_status & PCI_STAT_DEVSELT) >> 9);
636bd97c7ceSRobert Mustacchi 
637bd97c7ceSRobert Mustacchi 	/*
638bd97c7ceSRobert Mustacchi 	 * The ipin indicates which INTx value a device should have. Zero
639bd97c7ceSRobert Mustacchi 	 * indicates no INTx has been assigned.
640bd97c7ceSRobert Mustacchi 	 */
641bd97c7ceSRobert Mustacchi 	if (prop->ppd_ipin != 0) {
642bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "interrupts",
643bd97c7ceSRobert Mustacchi 		    prop->ppd_ipin);
644bd97c7ceSRobert Mustacchi 	}
645bd97c7ceSRobert Mustacchi 
646bd97c7ceSRobert Mustacchi 	/*
647bd97c7ceSRobert Mustacchi 	 * VGA class devices have required specific device_type and related
648bd97c7ceSRobert Mustacchi 	 * properties to be set. The same is true of ISA. Parent bridges and the
649bd97c7ceSRobert Mustacchi 	 * synthetic nexus nodes that represent root complexes ala npe, pci,
650bd97c7ceSRobert Mustacchi 	 * pcieb, etc. set the device type to either "pci" or "pciex", but that
651bd97c7ceSRobert Mustacchi 	 * is not done universally at this time. We should consider that for the
652bd97c7ceSRobert Mustacchi 	 * future.
653bd97c7ceSRobert Mustacchi 	 */
654bd97c7ceSRobert Mustacchi 	if (pci_prop_class_is_vga(prop)) {
655bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
656bd97c7ceSRobert Mustacchi 		    "device_type", "display");
657bd97c7ceSRobert Mustacchi 	} else if (pci_prop_class_is_isa(prop) &&
658bd97c7ceSRobert Mustacchi 	    (flags & PCI_PRD_COMPAT_ISA) != 0) {
659bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
660bd97c7ceSRobert Mustacchi 		    "device_type", "isa");
661bd97c7ceSRobert Mustacchi 	}
662bd97c7ceSRobert Mustacchi 
663bd97c7ceSRobert Mustacchi 	/*
664bd97c7ceSRobert Mustacchi 	 * Go through and add the model property. This utilizes the common PCI
665bd97c7ceSRobert Mustacchi 	 * class codes. Traditionally a PCIe->PCI bridge was treated specially
666bd97c7ceSRobert Mustacchi 	 * and given a unique label because of the fact it was crossing between
667bd97c7ceSRobert Mustacchi 	 * the protocols (though the opposite wasn't true for PCI->PCIe
668bd97c7ceSRobert Mustacchi 	 * bridges).
669bd97c7ceSRobert Mustacchi 	 *
670bd97c7ceSRobert Mustacchi 	 * The other traditional gotcha here is that any device whose class and
671bd97c7ceSRobert Mustacchi 	 * subclass indicated it was an IDE controller got that name.
672bd97c7ceSRobert Mustacchi 	 */
673bd97c7ceSRobert Mustacchi 	if ((prop->ppd_flags & PCI_PROP_F_PCIE) != 0 &&
674bd97c7ceSRobert Mustacchi 	    prop->ppd_pcie_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
675bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
676bd97c7ceSRobert Mustacchi 		    (char *)"PCIe-PCI bridge");
677bd97c7ceSRobert Mustacchi 	} else if (prop->ppd_class == PCI_CLASS_MASS &&
678bd97c7ceSRobert Mustacchi 	    prop->ppd_subclass == PCI_MASS_IDE) {
679bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
680bd97c7ceSRobert Mustacchi 		    (char *)"IDE controller");
681bd97c7ceSRobert Mustacchi 	} else {
682bd97c7ceSRobert Mustacchi 		const char *desc = NULL;
683bd97c7ceSRobert Mustacchi 
684bd97c7ceSRobert Mustacchi 		for (int i = 0; i < class_pci_items; i++) {
685bd97c7ceSRobert Mustacchi 			if (prop->ppd_class == class_pci[i].base_class &&
686bd97c7ceSRobert Mustacchi 			    prop->ppd_subclass == class_pci[i].sub_class &&
687bd97c7ceSRobert Mustacchi 			    prop->ppd_pi == class_pci[i].prog_class) {
688bd97c7ceSRobert Mustacchi 				desc = class_pci[i].actual_desc;
689bd97c7ceSRobert Mustacchi 				break;
690bd97c7ceSRobert Mustacchi 			}
691bd97c7ceSRobert Mustacchi 		}
692bd97c7ceSRobert Mustacchi 
693bd97c7ceSRobert Mustacchi 		if (desc == NULL) {
694bd97c7ceSRobert Mustacchi 			/*
695bd97c7ceSRobert Mustacchi 			 * Yes, we're not dealing with PNP strictly any more,
696bd97c7ceSRobert Mustacchi 			 * but this is the string we've traditionally used.
697bd97c7ceSRobert Mustacchi 			 */
698bd97c7ceSRobert Mustacchi 			desc = "Unknown class of pci/pnpbios device";
699bd97c7ceSRobert Mustacchi 		}
700bd97c7ceSRobert Mustacchi 
701bd97c7ceSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
702bd97c7ceSRobert Mustacchi 		    (char *)desc);
703bd97c7ceSRobert Mustacchi 	}
704bd97c7ceSRobert Mustacchi 
705bd97c7ceSRobert Mustacchi 	return (PCI_PROP_OK);
706bd97c7ceSRobert Mustacchi }
707bd97c7ceSRobert Mustacchi 
708bd97c7ceSRobert Mustacchi 
709bd97c7ceSRobert Mustacchi /*
710bd97c7ceSRobert Mustacchi  * This enumeration encodes the different possible forms of the alias
711bd97c7ceSRobert Mustacchi  * properties. In these definitions, the following groups of letters have
712bd97c7ceSRobert Mustacchi  * different means:
713bd97c7ceSRobert Mustacchi  *
714bd97c7ceSRobert Mustacchi  * "VD": Vendor ID,Device ID (1234,5678)
715bd97c7ceSRobert Mustacchi  * "SVSI": Subsystem Vendor ID, Subsystem ID
716bd97c7ceSRobert Mustacchi  * "R": Revision
717bd97c7ceSRobert Mustacchi  * "S": The string ,s to represent the disambiguated PCI subsystem alias
718bd97c7ceSRobert Mustacchi  * "P": The string ,p to represent the disambiguated PCI primary alias
719bd97c7ceSRobert Mustacchi  * "CSPI": Class, subclass, and Programming Interface
720bd97c7ceSRobert Mustacchi  * "CS": Class, subclass
721bd97c7ceSRobert Mustacchi  */
722bd97c7ceSRobert Mustacchi typedef enum {
723bd97c7ceSRobert Mustacchi 	PCI_ALIAS_VD_SVSI_R,
724bd97c7ceSRobert Mustacchi 	PCI_ALIAS_VD_SVSI,
725bd97c7ceSRobert Mustacchi 	PCI_ALIAS_SVSI_S,
726bd97c7ceSRobert Mustacchi 	PCI_ALIAS_SVSI,
727bd97c7ceSRobert Mustacchi 	PCI_ALIAS_VD_R,
728bd97c7ceSRobert Mustacchi 	PCI_ALIAS_VD_P,
729bd97c7ceSRobert Mustacchi 	PCI_ALIAS_VD,
730bd97c7ceSRobert Mustacchi 	PCI_ALIAS_CSPI,
731bd97c7ceSRobert Mustacchi 	PCI_ALIAS_CS,
732bd97c7ceSRobert Mustacchi 	PCI_ALIAS_MAX
733bd97c7ceSRobert Mustacchi } pci_alias_t;
734bd97c7ceSRobert Mustacchi 
735bd97c7ceSRobert Mustacchi /*
736bd97c7ceSRobert Mustacchi  * The upper bound on aliases is if everything is used once for PCIe and then
737bd97c7ceSRobert Mustacchi  * again for PCI. This is more than should be used.
738bd97c7ceSRobert Mustacchi  */
739bd97c7ceSRobert Mustacchi #define	PCI_MAX_ALIASES	(2 * PCI_ALIAS_MAX)
740bd97c7ceSRobert Mustacchi 
741bd97c7ceSRobert Mustacchi typedef enum {
742bd97c7ceSRobert Mustacchi 	/*
743bd97c7ceSRobert Mustacchi 	 * This flag indicates that a given alias should only be used for PCI
744bd97c7ceSRobert Mustacchi 	 * devices.
745bd97c7ceSRobert Mustacchi 	 */
746bd97c7ceSRobert Mustacchi 	PCI_ALIAS_F_PCI_ONLY		= 1 << 0,
747bd97c7ceSRobert Mustacchi 	/*
748bd97c7ceSRobert Mustacchi 	 * This flag indicates that this value should not be used for any device
749bd97c7ceSRobert Mustacchi 	 * with a type 1 header, aka PCI-PCI bridges.
750bd97c7ceSRobert Mustacchi 	 */
751bd97c7ceSRobert Mustacchi 	PCI_ALIAS_F_SKIP_BRIDGE		= 1 << 1,
752bd97c7ceSRobert Mustacchi 	/*
753bd97c7ceSRobert Mustacchi 	 * This flag indicates that we should create subsystem compatibility
754bd97c7ceSRobert Mustacchi 	 * IDs. We only expect this to be done on x86 (and SPARC historically).
755bd97c7ceSRobert Mustacchi 	 */
756bd97c7ceSRobert Mustacchi 	PCI_ALIAS_F_COMPAT		= 1 << 2,
757bd97c7ceSRobert Mustacchi 	/*
758bd97c7ceSRobert Mustacchi 	 * This flag indicates that we need to check whether we've banned the
759bd97c7ceSRobert Mustacchi 	 * subsystem ID due to duplication. This is still something we do even
760bd97c7ceSRobert Mustacchi 	 * when we don't have PCI_ALIAS_F_COMPAT set for the disambiguated
761bd97c7ceSRobert Mustacchi 	 * subsystem ID.
762bd97c7ceSRobert Mustacchi 	 */
763bd97c7ceSRobert Mustacchi 	PCI_ALIAS_F_CHECK_SUBSYS	= 1 << 3
764bd97c7ceSRobert Mustacchi } pci_alias_flags_t;
765bd97c7ceSRobert Mustacchi 
766bd97c7ceSRobert Mustacchi typedef struct {
767bd97c7ceSRobert Mustacchi 	pci_alias_t pad_type;
768bd97c7ceSRobert Mustacchi 	pci_alias_flags_t pad_flags;
769bd97c7ceSRobert Mustacchi } pci_alias_data_t;
770bd97c7ceSRobert Mustacchi 
771bd97c7ceSRobert Mustacchi static const pci_alias_data_t pci_alias_table[] = {
772bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_VD_SVSI_R, 0 },
773bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_VD_SVSI, 0 },
774bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_SVSI_S, PCI_ALIAS_F_PCI_ONLY | PCI_ALIAS_F_CHECK_SUBSYS },
775bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_SVSI, PCI_ALIAS_F_PCI_ONLY | PCI_ALIAS_F_SKIP_BRIDGE |
776bd97c7ceSRobert Mustacchi 	    PCI_ALIAS_F_COMPAT | PCI_ALIAS_F_CHECK_SUBSYS },
777bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_VD_R, 0 },
778bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_VD_P, PCI_ALIAS_F_PCI_ONLY },
779bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_VD, 0 },
780bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_CSPI, 0 },
781bd97c7ceSRobert Mustacchi 	{ PCI_ALIAS_CS, 0 },
782bd97c7ceSRobert Mustacchi };
783bd97c7ceSRobert Mustacchi 
784bd97c7ceSRobert Mustacchi /*
785bd97c7ceSRobert Mustacchi  * Our big theory statement talks about cases where we already know that PCI IDs
786bd97c7ceSRobert Mustacchi  * have had overlap with subsystems and them not being appropriate. The
787bd97c7ceSRobert Mustacchi  * following table describes how to match
788bd97c7ceSRobert Mustacchi  */
789bd97c7ceSRobert Mustacchi typedef enum {
790bd97c7ceSRobert Mustacchi 	PCI_PROP_NSM_VID_CLASS,
791bd97c7ceSRobert Mustacchi 	PCI_PROP_NSM_SUBSYS
792bd97c7ceSRobert Mustacchi } pci_prop_no_subsys_match_t;
793bd97c7ceSRobert Mustacchi 
794bd97c7ceSRobert Mustacchi typedef boolean_t (*pci_prop_no_subsys_class_f)(const pci_prop_data_t *);
795bd97c7ceSRobert Mustacchi typedef struct pci_prop_no_subsys {
796bd97c7ceSRobert Mustacchi 	pci_prop_no_subsys_match_t	ppnsm_type;
797bd97c7ceSRobert Mustacchi 	uint16_t			ppnsm_vid;
798bd97c7ceSRobert Mustacchi 	uint16_t			ppnsm_did;
799bd97c7ceSRobert Mustacchi 	uint16_t			ppnsm_subvid;
800bd97c7ceSRobert Mustacchi 	uint16_t			ppnsm_subsys;
801bd97c7ceSRobert Mustacchi 	pci_prop_no_subsys_class_f	ppnsm_class;
802bd97c7ceSRobert Mustacchi } pci_prop_no_subsys_t;
803bd97c7ceSRobert Mustacchi 
804bd97c7ceSRobert Mustacchi static const pci_prop_no_subsys_t pci_prop_no_subsys[] = {
805bd97c7ceSRobert Mustacchi 	/*
806bd97c7ceSRobert Mustacchi 	 * We've historically blocked nVidia subsystems because of subsystem
807bd97c7ceSRobert Mustacchi 	 * reuse.
808bd97c7ceSRobert Mustacchi 	 */
809bd97c7ceSRobert Mustacchi 	{ .ppnsm_type = PCI_PROP_NSM_VID_CLASS, .ppnsm_vid = 0x10de,
810bd97c7ceSRobert Mustacchi 	    .ppnsm_class = pci_prop_class_is_vga },
811bd97c7ceSRobert Mustacchi 	/*
812bd97c7ceSRobert Mustacchi 	 * 8086,166 is the Ivy Bridge built-in graphics controller on some
813bd97c7ceSRobert Mustacchi 	 * models. Unfortunately 8086,2044 is the Skylake Server processor
814bd97c7ceSRobert Mustacchi 	 * memory channel device. The Ivy Bridge device uses the Skylake
815bd97c7ceSRobert Mustacchi 	 * ID as its sub-device ID. The GPU is not a memory controller DIMM
816bd97c7ceSRobert Mustacchi 	 * channel.
817bd97c7ceSRobert Mustacchi 	 */
818bd97c7ceSRobert Mustacchi 	{ .ppnsm_type = PCI_PROP_NSM_SUBSYS, .ppnsm_vid = 0x8086,
819bd97c7ceSRobert Mustacchi 	    .ppnsm_did = 0x166, .ppnsm_subvid = 0x8086, .ppnsm_subsys = 0x2044 }
820bd97c7ceSRobert Mustacchi };
821bd97c7ceSRobert Mustacchi 
822bd97c7ceSRobert Mustacchi static boolean_t
pci_prop_skip_subsys(const pci_prop_data_t * prop)823bd97c7ceSRobert Mustacchi pci_prop_skip_subsys(const pci_prop_data_t *prop)
824bd97c7ceSRobert Mustacchi {
825bd97c7ceSRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(pci_prop_no_subsys); i++) {
826bd97c7ceSRobert Mustacchi 		const pci_prop_no_subsys_t *p = &pci_prop_no_subsys[i];
827bd97c7ceSRobert Mustacchi 		switch (p->ppnsm_type) {
828bd97c7ceSRobert Mustacchi 		case PCI_PROP_NSM_VID_CLASS:
829bd97c7ceSRobert Mustacchi 			if (prop->ppd_vendid == p->ppnsm_vid &&
830bd97c7ceSRobert Mustacchi 			    p->ppnsm_class(prop)) {
831bd97c7ceSRobert Mustacchi 				return (B_TRUE);
832bd97c7ceSRobert Mustacchi 			}
833bd97c7ceSRobert Mustacchi 			break;
834bd97c7ceSRobert Mustacchi 		case PCI_PROP_NSM_SUBSYS:
835bd97c7ceSRobert Mustacchi 			if (prop->ppd_vendid == p->ppnsm_vid &&
836bd97c7ceSRobert Mustacchi 			    prop->ppd_devid == p->ppnsm_did &&
837bd97c7ceSRobert Mustacchi 			    prop->ppd_subvid == p->ppnsm_subvid &&
838bd97c7ceSRobert Mustacchi 			    prop->ppd_subsys == p->ppnsm_subsys) {
839bd97c7ceSRobert Mustacchi 				return (B_TRUE);
840bd97c7ceSRobert Mustacchi 			}
841bd97c7ceSRobert Mustacchi 			break;
842bd97c7ceSRobert Mustacchi 		}
843bd97c7ceSRobert Mustacchi 	}
844bd97c7ceSRobert Mustacchi 	return (B_FALSE);
845bd97c7ceSRobert Mustacchi }
846bd97c7ceSRobert Mustacchi 
847bd97c7ceSRobert Mustacchi static void
pci_prop_alias_pass(const pci_prop_data_t * prop,char ** alias,uint_t * nalias,pci_prd_compat_flags_t compat,boolean_t force_pci)848bd97c7ceSRobert Mustacchi pci_prop_alias_pass(const pci_prop_data_t *prop, char **alias, uint_t *nalias,
849bd97c7ceSRobert Mustacchi     pci_prd_compat_flags_t compat, boolean_t force_pci)
850bd97c7ceSRobert Mustacchi {
851bd97c7ceSRobert Mustacchi 	boolean_t is_pci = force_pci ||
852bd97c7ceSRobert Mustacchi 	    (prop->ppd_flags & PCI_PROP_F_PCIE) == 0;
853bd97c7ceSRobert Mustacchi 	const char *prefix = is_pci ? "pci" : "pciex";
854bd97c7ceSRobert Mustacchi 	boolean_t subsys_valid = prop->ppd_subvid != 0;
855bd97c7ceSRobert Mustacchi 
856bd97c7ceSRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(pci_alias_table); i++) {
857bd97c7ceSRobert Mustacchi 		const pci_alias_data_t *a = &pci_alias_table[i];
858bd97c7ceSRobert Mustacchi 
859bd97c7ceSRobert Mustacchi 		if ((a->pad_flags & PCI_ALIAS_F_PCI_ONLY) != 0 && !is_pci) {
860bd97c7ceSRobert Mustacchi 			continue;
861bd97c7ceSRobert Mustacchi 		}
862bd97c7ceSRobert Mustacchi 
863bd97c7ceSRobert Mustacchi 		if ((a->pad_flags & PCI_ALIAS_F_SKIP_BRIDGE) != 0 &&
864bd97c7ceSRobert Mustacchi 		    prop->ppd_header == PCI_HEADER_PPB) {
865bd97c7ceSRobert Mustacchi 			continue;
866bd97c7ceSRobert Mustacchi 		}
867bd97c7ceSRobert Mustacchi 
868bd97c7ceSRobert Mustacchi 		if ((a->pad_flags & PCI_ALIAS_F_COMPAT) != 0 &&
869bd97c7ceSRobert Mustacchi 		    (compat & PCI_PRD_COMPAT_SUBSYS) == 0) {
870bd97c7ceSRobert Mustacchi 			continue;
871bd97c7ceSRobert Mustacchi 		}
872bd97c7ceSRobert Mustacchi 
873bd97c7ceSRobert Mustacchi 		if ((a->pad_flags & PCI_ALIAS_F_CHECK_SUBSYS) != 0 &&
874bd97c7ceSRobert Mustacchi 		    pci_prop_skip_subsys(prop)) {
875bd97c7ceSRobert Mustacchi 			continue;
876bd97c7ceSRobert Mustacchi 		}
877bd97c7ceSRobert Mustacchi 
878bd97c7ceSRobert Mustacchi 		switch (a->pad_type) {
879bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_VD_SVSI_R:
880bd97c7ceSRobert Mustacchi 			if (!subsys_valid)
881bd97c7ceSRobert Mustacchi 				continue;
882bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%s%x,%x.%x.%x.%x",
883bd97c7ceSRobert Mustacchi 			    prefix, prop->ppd_vendid, prop->ppd_devid,
884bd97c7ceSRobert Mustacchi 			    prop->ppd_subvid, prop->ppd_subsys,
885bd97c7ceSRobert Mustacchi 			    prop->ppd_rev);
886bd97c7ceSRobert Mustacchi 			break;
887bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_VD_SVSI:
888bd97c7ceSRobert Mustacchi 			if (!subsys_valid)
889bd97c7ceSRobert Mustacchi 				continue;
890bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%s%x,%x.%x.%x", prefix,
891bd97c7ceSRobert Mustacchi 			    prop->ppd_vendid, prop->ppd_devid,
892bd97c7ceSRobert Mustacchi 			    prop->ppd_subvid, prop->ppd_subsys);
893bd97c7ceSRobert Mustacchi 			break;
894bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_SVSI_S:
895bd97c7ceSRobert Mustacchi 			if (!subsys_valid)
896bd97c7ceSRobert Mustacchi 				continue;
897bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%s%x,%x,s", prefix,
898bd97c7ceSRobert Mustacchi 			    prop->ppd_subvid, prop->ppd_subsys);
899bd97c7ceSRobert Mustacchi 			break;
900bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_SVSI:
901bd97c7ceSRobert Mustacchi 			if (!subsys_valid)
902bd97c7ceSRobert Mustacchi 				continue;
903bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%s%x,%x", prefix,
904bd97c7ceSRobert Mustacchi 			    prop->ppd_subvid, prop->ppd_subsys);
905bd97c7ceSRobert Mustacchi 			break;
906bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_VD_R:
907bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%s%x,%x.%x", prefix,
908bd97c7ceSRobert Mustacchi 			    prop->ppd_vendid, prop->ppd_devid, prop->ppd_rev);
909bd97c7ceSRobert Mustacchi 			break;
910bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_VD_P:
911bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%s%x,%x,p", prefix,
912bd97c7ceSRobert Mustacchi 			    prop->ppd_vendid, prop->ppd_devid);
913bd97c7ceSRobert Mustacchi 			break;
914bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_VD:
915bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%s%x,%x", prefix,
916bd97c7ceSRobert Mustacchi 			    prop->ppd_vendid, prop->ppd_devid);
917bd97c7ceSRobert Mustacchi 			break;
918bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_CSPI:
919bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%sclass,%02x%02x%02x",
920bd97c7ceSRobert Mustacchi 			    prefix, prop->ppd_class, prop->ppd_subclass,
921bd97c7ceSRobert Mustacchi 			    prop->ppd_pi);
922bd97c7ceSRobert Mustacchi 			break;
923bd97c7ceSRobert Mustacchi 		case PCI_ALIAS_CS:
924bd97c7ceSRobert Mustacchi 			alias[*nalias] = kmem_asprintf("%sclass,%02x%02x",
925bd97c7ceSRobert Mustacchi 			    prefix, prop->ppd_class, prop->ppd_subclass);
926bd97c7ceSRobert Mustacchi 			break;
927bd97c7ceSRobert Mustacchi 		default:
928bd97c7ceSRobert Mustacchi 			panic("encountered unknown alias type: 0x%x",
929bd97c7ceSRobert Mustacchi 			    a->pad_type);
930bd97c7ceSRobert Mustacchi 		}
931bd97c7ceSRobert Mustacchi 
932bd97c7ceSRobert Mustacchi 		*nalias = *nalias + 1;
933bd97c7ceSRobert Mustacchi 		ASSERT3U(*nalias, <=, PCI_MAX_ALIASES);
934bd97c7ceSRobert Mustacchi 	}
935bd97c7ceSRobert Mustacchi }
936bd97c7ceSRobert Mustacchi 
937bd97c7ceSRobert Mustacchi /*
938bd97c7ceSRobert Mustacchi  * Go through the messy process of creating the compatible property. See the
939bd97c7ceSRobert Mustacchi  * theory statement for more info.
940bd97c7ceSRobert Mustacchi  */
941bd97c7ceSRobert Mustacchi pci_prop_failure_t
pci_prop_set_compatible(dev_info_t * dip,const pci_prop_data_t * prop)942bd97c7ceSRobert Mustacchi pci_prop_set_compatible(dev_info_t *dip, const pci_prop_data_t *prop)
943bd97c7ceSRobert Mustacchi {
944bd97c7ceSRobert Mustacchi 	char *alias[PCI_MAX_ALIASES];
945bd97c7ceSRobert Mustacchi 	uint_t nalias = 0;
946bd97c7ceSRobert Mustacchi 	pci_prd_compat_flags_t compat = pci_prd_compat_flags();
947bd97c7ceSRobert Mustacchi 	boolean_t two_sets = (compat & PCI_PRD_COMPAT_PCI_NODE_NAME) != 0;
948bd97c7ceSRobert Mustacchi 
949bd97c7ceSRobert Mustacchi 	pci_prop_alias_pass(prop, alias, &nalias, compat, B_FALSE);
950bd97c7ceSRobert Mustacchi 	if (two_sets && (prop->ppd_flags & PCI_PROP_F_PCIE) != 0) {
951bd97c7ceSRobert Mustacchi 		pci_prop_alias_pass(prop, alias, &nalias, compat, B_TRUE);
952bd97c7ceSRobert Mustacchi 	}
953bd97c7ceSRobert Mustacchi 
954bd97c7ceSRobert Mustacchi 	(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
955bd97c7ceSRobert Mustacchi 	    alias, nalias);
956bd97c7ceSRobert Mustacchi 	for (uint_t i = 0; i < nalias; i++) {
957bd97c7ceSRobert Mustacchi 		strfree(alias[i]);
958bd97c7ceSRobert Mustacchi 	}
959bd97c7ceSRobert Mustacchi 	return (PCI_PROP_OK);
960bd97c7ceSRobert Mustacchi }
961