1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * i86pc Generic hostbridge/pciex/pci enumerator
28 *
29 * hostbridge/pciexrc/pcibus topo nodes are created per SMBIOS type 138
30 * (SUN_OEM_PCIEXRC) records. Each type 138 record can either represent
31 * a hostbridge or a pciexrc/pcibus determined by whether it points to
32 * a baseboard record or another type 138 record.
33 *
34 * x86pi_gen_hbr() is called when a new hostbridge node needs to be created..
35 * It then searches all the type 138 records that connected to it. For each
36 * of the records, bdf is compared to find a matching di_node. If the
37 * di_node is a pciex root port, a pciexrc (bad name!) node will be created.
38 * When pciexrc creation is done, or the di_node is a pcibus, in either
39 * case the pcibus module will loaded to enumerate pciexbus/pcibus etc.
40 *
41 * The enumeration uses did routines heavily, which requires a did hash
42 * pointer stored in x86pi's module-specific area.
43 */
44
45 #include <sys/types.h>
46 #include <strings.h>
47 #include <fm/topo_mod.h>
48 #include <fm/topo_hc.h>
49 #include <sys/systeminfo.h>
50 #include <sys/smbios_impl.h>
51 #include <sys/fm/protocol.h>
52 #include <x86pi_impl.h>
53 #include <did.h>
54 #include <did_impl.h>
55 #include <did_props.h>
56 #include <hostbridge.h>
57
58 #define PCI_ENUM "pcibus"
59 #define PCI_ENUMR_VERS 1
60 #define MAX_HB_BUSES 255
61
62 extern txprop_t RC_common_props[], HB_common_props[], ExHB_common_props[];
63 extern int RC_propcnt, HB_propcnt, ExHB_propcnt;
64
65 static topo_mod_t *pcimp = NULL;
66
67 int
x86pi_hbr_enum_init(topo_mod_t * mod)68 x86pi_hbr_enum_init(topo_mod_t *mod)
69 {
70 const char *f = "x86pi_hbr_enum_init";
71
72 if (did_hash_init(mod) < 0) {
73 topo_mod_dprintf(mod, "%s: did_hash_init() failed.\n", f);
74 return (-1);
75 }
76
77 if ((pcimp = topo_mod_load(mod, PCI_ENUM, PCI_ENUMR_VERS)) == NULL) {
78 topo_mod_dprintf(mod,
79 "%s: %s enumerator could not load %s.\n",
80 f, HOSTBRIDGE, PCI_ENUM);
81 did_hash_fini(mod);
82 return (-1);
83 }
84
85 return (0);
86 }
87
88 void
x86pi_hbr_enum_fini(topo_mod_t * mod)89 x86pi_hbr_enum_fini(topo_mod_t *mod)
90 {
91 did_hash_fini(mod);
92 topo_mod_unload(pcimp);
93 pcimp = NULL;
94 }
95
96 static int
pciex_process(topo_mod_t * mod,tnode_t * tn_hbr,di_node_t rcn,topo_instance_t rci)97 pciex_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t rcn,
98 topo_instance_t rci)
99 {
100 did_t *did;
101 int rv;
102 tnode_t *tn_rc;
103 x86pi_hcfmri_t hcfmri = {0};
104 tnode_t *tn_bb = topo_node_parent(tn_hbr);
105 const char *f = "pciexrc_process";
106
107 if ((did = did_create(mod, rcn, topo_node_instance(tn_bb),
108 topo_node_instance(tn_hbr), rci, TRUST_BDF)) == NULL)
109 return (NULL);
110
111 did_markrc(did);
112
113 /*
114 * Let did set the hostbridge properties excluding FRU and label.
115 */
116 (void) did_props_set(tn_hbr, did, ExHB_common_props, ExHB_propcnt - 2);
117
118 if (topo_node_range_create(mod, tn_hbr, PCIEX_ROOT, 0,
119 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
120 topo_mod_dprintf(mod,
121 "%s: create child range for %s failed: %s\n",
122 f, PCIEX_ROOT, topo_mod_errmsg(mod));
123 return (-1);
124 }
125
126 hcfmri.hc_name = PCIEX_ROOT;
127 hcfmri.instance = rci;
128 rv = x86pi_enum_generic(mod, &hcfmri, tn_hbr, tn_hbr, &tn_rc, 0);
129 if (rv != 0) {
130 topo_mod_dprintf(mod, "%s: failed to create %s = %d\n",
131 f, PCIEX_ROOT, rci);
132 return (-1);
133 }
134
135 /*
136 * pcibus enumerator requires di_node_t be set in node specific
137 */
138 topo_node_setspecific(tn_rc, rcn);
139
140 /*
141 * Let did set the RC properties excluding FRU, and label.
142 */
143 if (did_props_set(tn_rc, did, RC_common_props, RC_propcnt - 2) < 0) {
144 topo_mod_dprintf(mod, "%s: did_props_set failed for %s = %d\n",
145 f, PCIEX_ROOT, rci);
146 topo_node_unbind(tn_rc);
147 return (-1);
148 }
149
150 if (topo_node_range_create(mod, tn_rc, PCIEX_BUS, 0,
151 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
152 topo_mod_dprintf(mod,
153 "%s: create child range for %s failed: %s\n",
154 f, PCIEX_BUS, topo_mod_errmsg(mod));
155 return (-1);
156 }
157
158 return (topo_mod_enumerate(mod, tn_rc, PCI_BUS, PCIEX_BUS,
159 0, MAX_HB_BUSES, did));
160 }
161
162 static int
pci_process(topo_mod_t * mod,tnode_t * tn_hbr,di_node_t bn)163 pci_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t bn)
164 {
165 did_t *did;
166 tnode_t *tn_bb = topo_node_parent(tn_hbr);
167
168 if ((did = did_create(mod, bn, topo_node_instance(tn_bb),
169 topo_node_instance(tn_hbr), NO_RC, TRUST_BDF)) == NULL)
170 return (-1);
171
172 /*
173 * Let did set the hostbridge properties excluding FRU and label.
174 */
175 (void) did_props_set(tn_hbr, did, HB_common_props, HB_propcnt - 2);
176
177 if (topo_node_range_create(mod, tn_hbr, PCI_BUS, 0,
178 MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
179 topo_mod_dprintf(mod, "create child range for %s failed: %s\n",
180 PCI_BUS, topo_mod_errmsg(mod));
181 return (-1);
182 }
183
184 return (topo_mod_enumerate(mod, tn_hbr, PCI_BUS, PCI_BUS,
185 0, MAX_HB_BUSES, did));
186 }
187
188 static int
x86pi_gen_pci_pciexrc(topo_mod_t * mod,tnode_t * tn_hbr,uint16_t bdf,topo_instance_t * rcip)189 x86pi_gen_pci_pciexrc(topo_mod_t *mod, tnode_t *tn_hbr, uint16_t bdf,
190 topo_instance_t *rcip)
191 {
192 di_node_t devtree, pnode, cnode;
193
194 topo_mod_dprintf(mod, "creating pci/pciexrc node bdf = %#x\n",
195 (int)bdf);
196
197 devtree = topo_mod_devinfo(mod);
198 if (devtree == DI_NODE_NIL) {
199 topo_mod_dprintf(mod, "devinfo init failed.\n");
200 return (-1);
201 }
202
203 for (pnode = di_drv_first_node(PCI, devtree);
204 pnode != DI_NODE_NIL; pnode = di_drv_next_node(pnode))
205 if (x86pi_bdf(mod, pnode) == bdf)
206 return (pci_process(mod, tn_hbr, pnode));
207
208 pnode = di_drv_first_node(NPE, devtree);
209 while (pnode != DI_NODE_NIL) {
210 for (cnode = di_child_node(pnode); cnode != DI_NODE_NIL;
211 cnode = di_sibling_node(cnode)) {
212 if (di_driver_name(cnode) == NULL ||
213 x86pi_bdf(mod, cnode) != bdf)
214 continue;
215
216 if (strcmp(di_driver_name(cnode), PCI_PCI) == 0)
217 return (pci_process(mod, tn_hbr, cnode));
218
219 if (strcmp(di_driver_name(cnode), PCIEB) == 0)
220 return (pciex_process(mod, tn_hbr,
221 cnode, (*rcip)++));
222
223 topo_mod_dprintf(mod, "no matching driver found: "
224 "bdf = %#x\n", (int)bdf);
225 }
226 pnode = di_drv_next_node(pnode);
227 }
228
229 topo_mod_dprintf(mod, "no matching bdf found: bdf = %#x\n", (int)bdf);
230
231 return (0);
232 }
233
234 int
x86pi_gen_hbr(topo_mod_t * mod,tnode_t * tn_bb,int hbr_smbid,topo_instance_t hbri,topo_instance_t * rcip)235 x86pi_gen_hbr(topo_mod_t *mod, tnode_t *tn_bb,
236 int hbr_smbid, topo_instance_t hbri, topo_instance_t *rcip)
237 {
238 x86pi_hcfmri_t hcfmri = {0};
239 tnode_t *tn_hbr;
240 smbs_cnt_t *smbc = &stypes[SUN_OEM_PCIEXRC];
241 smbios_pciexrc_t smb_rc;
242 int i, rv, err = 0;
243 const char *f = "x86pi_gen_hbr";
244 smbios_hdl_t *shp;
245
246 shp = topo_mod_smbios(mod);
247 if (shp == NULL)
248 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
249
250 hcfmri.hc_name = HOSTBRIDGE;
251 hcfmri.instance = hbri;
252
253 /* create and bind the "hostbridge" node */
254 rv = x86pi_enum_generic(mod, &hcfmri, tn_bb, tn_bb, &tn_hbr, 0);
255 if (rv != 0) {
256 topo_mod_dprintf(mod, "%s: failed to create %s = %d\n",
257 f, HOSTBRIDGE, hbri);
258 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
259 }
260
261 /*
262 * Walk the smbios records and create the pci/pciexrc nodes
263 */
264 for (i = 0; i < smbc->count; i++) {
265 if (smbios_info_pciexrc(shp, smbc->ids[i].id, &smb_rc) != 0)
266 topo_mod_dprintf(mod,
267 "%s: failed: id = %d\n", f, (int)smbc->ids[i].id);
268 else if (smb_rc.smbpcie_bb == hbr_smbid &&
269 x86pi_gen_pci_pciexrc(mod, tn_hbr, smb_rc.smbpcie_bdf,
270 rcip) != 0)
271 err++;
272 }
273
274 return (err == 0 ? 0 : topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
275 }
276