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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 #include <libdevinfo.h>
30 #include <fm/topo_mod.h>
31 #include <fm/topo_hc.h>
32 #include <sys/fm/protocol.h>
35 static const topo_pgroup_info_t io_pgroup
=
36 { TOPO_PGROUP_IO
, TOPO_STABILITY_PRIVATE
, TOPO_STABILITY_PRIVATE
, 1 };
37 static const topo_pgroup_info_t pci_pgroup
=
38 { TOPO_PGROUP_PCI
, TOPO_STABILITY_PRIVATE
, TOPO_STABILITY_PRIVATE
, 1 };
41 * Check the root complex device node for a slot-names property.
44 opl_get_slot_name(topo_mod_t
*mod
, di_node_t n
)
46 di_prom_handle_t ptp
= DI_PROM_HANDLE_NIL
;
47 di_prom_prop_t pp
= DI_PROM_PROP_NIL
;
50 if ((ptp
= topo_mod_prominfo(mod
)) == DI_PROM_PROP_NIL
)
53 for (pp
= di_prom_prop_next(ptp
, n
, pp
);
54 pp
!= DI_PROM_PROP_NIL
;
55 pp
= di_prom_prop_next(ptp
, n
, pp
)) {
56 if (strcmp(di_prom_prop_name(pp
), OPL_SLOT_NAMES
) == 0) {
57 if (di_prom_prop_data(pp
, &buf
) <= sizeof (uint32_t))
59 return ((const char *)&buf
[4]);
66 opl_node_create(topo_mod_t
*mp
, tnode_t
*parent
, const char *name
, int inst
,
71 nvlist_t
*auth
= topo_mod_auth(mp
, parent
);
73 if (parent
== NULL
|| inst
< 0) {
78 if ((fmri
= topo_mod_hcfmri(mp
, parent
, FM_HC_SCHEME_VERSION
, name
,
79 inst
, NULL
, auth
, NULL
, NULL
, NULL
)) == NULL
) {
80 topo_mod_dprintf(mp
, "create of tnode for %s failed: %s",
81 name
, topo_strerror(topo_mod_errno(mp
)));
87 /* Create and bind node */
88 node
= topo_node_bind(mp
, parent
, name
, inst
, fmri
);
91 topo_mod_dprintf(mp
, "unable to bind root complex: %s\n",
92 topo_strerror(topo_mod_errno(mp
)));
93 return (NULL
); /* mod_errno already set */
97 topo_node_setspecific(node
, priv
);
103 * Create a root complex node.
106 opl_rc_node_create(topo_mod_t
*mp
, tnode_t
*parent
, di_node_t dnode
, int inst
)
110 const char *slot_name
;
114 rcn
= opl_node_create(mp
, parent
, PCIEX_ROOT
, inst
, (void *)dnode
);
120 * If this root complex connects to a slot, it will have a
121 * slot-names property.
123 slot_name
= opl_get_slot_name(mp
, dnode
);
128 (void) snprintf(fru_str
, sizeof (fru_str
), "hc:///component=%s",
130 if (topo_mod_str2nvl(mp
, fru_str
, &fru_fmri
) == 0) {
131 (void) topo_node_fru_set(rcn
, fru_fmri
, 0, &err
);
132 nvlist_free(fru_fmri
);
135 (void) topo_node_label_set(rcn
, (char *)slot_name
, &err
);
137 /* Inherit parent FRU's label */
138 (void) topo_node_fru_set(rcn
, NULL
, 0, &err
);
139 (void) topo_node_label_set(rcn
, NULL
, &err
);
143 * Set ASRU to be the dev-scheme ASRU
145 if ((dnpath
= di_devfs_path(dnode
)) != NULL
) {
148 fmri
= topo_mod_devfmri(mp
, FM_DEV_SCHEME_VERSION
,
152 "dev:///%s fmri creation failed.\n",
154 (void) topo_mod_seterrno(mp
, err
);
155 di_devfs_path_free(dnpath
);
158 if (topo_node_asru_set(rcn
, fmri
, 0, &err
) < 0) {
159 topo_mod_dprintf(mp
, "topo_node_asru_set failed\n");
160 (void) topo_mod_seterrno(mp
, err
);
162 di_devfs_path_free(dnpath
);
167 topo_mod_dprintf(mp
, "NULL di_devfs_path.\n");
171 * Set pciexrc properties for root complex nodes
174 /* Add the io and pci property groups */
175 if (topo_pgroup_create(rcn
, &io_pgroup
, &err
) < 0) {
176 topo_mod_dprintf(mp
, "topo_pgroup_create failed\n");
177 di_devfs_path_free(dnpath
);
178 (void) topo_mod_seterrno(mp
, err
);
181 if (topo_pgroup_create(rcn
, &pci_pgroup
, &err
) < 0) {
182 topo_mod_dprintf(mp
, "topo_pgroup_create failed\n");
183 di_devfs_path_free(dnpath
);
184 (void) topo_mod_seterrno(mp
, err
);
187 /* Add the devfs path property */
189 if (topo_prop_set_string(rcn
, TOPO_PGROUP_IO
, TOPO_IO_DEV
,
190 TOPO_PROP_IMMUTABLE
, dnpath
, &err
) != 0) {
191 topo_mod_dprintf(mp
, "Failed to set DEV property\n");
192 di_devfs_path_free(dnpath
);
193 (void) topo_mod_seterrno(mp
, err
);
195 di_devfs_path_free(dnpath
);
197 /* Oberon device type is always "pciex" */
198 if (topo_prop_set_string(rcn
, TOPO_PGROUP_IO
, TOPO_IO_DEVTYPE
,
199 TOPO_PROP_IMMUTABLE
, OPL_PX_DEVTYPE
, &err
) != 0) {
200 topo_mod_dprintf(mp
, "Failed to set DEVTYPE property\n");
202 /* Oberon driver is always "px" */
203 if (topo_prop_set_string(rcn
, TOPO_PGROUP_IO
, TOPO_IO_DRIVER
,
204 TOPO_PROP_IMMUTABLE
, OPL_PX_DRV
, &err
) != 0) {
205 topo_mod_dprintf(mp
, "Failed to set DRIVER property\n");
207 if ((mod
= topo_mod_modfmri(mp
, FM_MOD_SCHEME_VERSION
, OPL_PX_DRV
))
208 == NULL
|| topo_prop_set_fmri(rcn
, TOPO_PGROUP_IO
,
209 TOPO_IO_MODULE
, TOPO_PROP_IMMUTABLE
, mod
, &err
) != 0) {
210 topo_mod_dprintf(mp
, "Failed to set MODULE property\n");
214 /* This is a PCIEX Root Complex */
215 if (topo_prop_set_string(rcn
, TOPO_PGROUP_PCI
, TOPO_PCI_EXCAP
,
216 TOPO_PROP_IMMUTABLE
, PCIEX_ROOT
, &err
) != 0) {
217 topo_mod_dprintf(mp
, "Failed to set EXCAP property\n");
219 /* BDF of Oberon root complex is constant */
220 if (topo_prop_set_string(rcn
, TOPO_PGROUP_PCI
,
221 TOPO_PCI_BDF
, TOPO_PROP_IMMUTABLE
, OPL_PX_BDF
, &err
) != 0) {
222 topo_mod_dprintf(mp
, "Failed to set EXCAP property\n");
225 /* Make room for children */
226 (void) topo_node_range_create(mp
, rcn
, PCIEX_BUS
, 0, OPL_BUS_MAX
);
231 * Create a hostbridge node.
234 opl_hb_node_create(topo_mod_t
*mp
, tnode_t
*parent
, int inst
)
239 hbn
= opl_node_create(mp
, parent
, HOSTBRIDGE
, inst
, NULL
);
244 /* Inherit parent FRU's label */
245 (void) topo_node_fru_set(hbn
, NULL
, 0, &err
);
246 (void) topo_node_label_set(hbn
, NULL
, &err
);
248 /* Make room for children */
249 (void) topo_node_range_create(mp
, hbn
, PCIEX_ROOT
, 0, OPL_RC_MAX
);
255 * opl_hb_enum gets the ioboard instance passed in, and determines the
256 * hostbridge and root complex instances numbers based on the bus addresses.
259 opl_hb_enum(topo_mod_t
*mp
, const ioboard_contents_t
*iob
, tnode_t
*ion
,
269 /* Load the pcibus module. We'll need it later. */
270 pcimod
= topo_mod_load(mp
, PCI_BUS
, PCI_BUS_VERS
);
271 if (pcimod
== NULL
) {
272 topo_mod_dprintf(mp
, "can't load pcibus module: %s\n",
273 topo_strerror(topo_mod_errno(mp
)));
277 /* For each hostbridge on an ioboard... */
278 for (hb
= 0; hb
< OPL_HB_MAX
; hb
++) {
280 /* For each root complex in a hostbridge... */
281 for (rc
= 0; rc
< OPL_RC_MAX
; rc
++) {
282 p
= iob
->rcs
[hb
][rc
];
283 /* If no root complex, continue */
284 if (p
== DI_NODE_NIL
) {
288 /* The root complex exists! */
289 topo_mod_dprintf(mp
, "declaring "
290 "/chassis=0/ioboard=%d/hostbridge=%d/pciexrc=%d\n",
294 * If we haven't created a hostbridge node yet, do it
297 if (hbnode
== NULL
) {
298 hbnode
= opl_hb_node_create(mp
, ion
, hb
);
299 if (hbnode
== NULL
) {
301 "unable to create hbnode: %s\n",
302 topo_strerror(topo_mod_errno(mp
)));
303 topo_mod_unload(pcimod
);
309 /* Create the root complex node */
310 rcnode
= opl_rc_node_create(mp
, hbnode
, p
, rc
);
311 if (rcnode
== NULL
) {
313 "unable to create rcnode: %s\n",
314 topo_strerror(topo_mod_errno(mp
)));
315 topo_mod_unload(pcimod
);
319 /* Enumerate pcibus nodes under the root complex */
320 if (topo_mod_enumerate(pcimod
, rcnode
,
321 PCI_BUS
, PCIEX_BUS
, 0, 255, NULL
) != 0) {
323 "error enumerating pcibus: %s\n",
324 topo_strerror(topo_mod_errno(mp
)));
325 topo_mod_unload(pcimod
);
330 topo_mod_unload(pcimod
);