xref: /titanic_41/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_hostbridge.c (revision 186d582bd9dbcd38e0aeea49036d47d3426a3536)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <string.h>
28 #include <strings.h>
29 #include <libdevinfo.h>
30 #include <fm/topo_mod.h>
31 #include <fm/topo_hc.h>
32 #include <sys/fm/protocol.h>
33 #include "opl_topo.h"
34 
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 };
39 
40 /*
41  * Check the root complex device node for a slot-names property.
42  */
43 const char *
opl_get_slot_name(topo_mod_t * mod,di_node_t n)44 opl_get_slot_name(topo_mod_t *mod, di_node_t n)
45 {
46 	di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
47 	di_prom_prop_t pp = DI_PROM_PROP_NIL;
48 	uchar_t *buf;
49 
50 	if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_PROP_NIL)
51 		return (NULL);
52 
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))
58 				continue;
59 			return ((const char *)&buf[4]);
60 		}
61 	}
62 	return (NULL);
63 }
64 
65 static tnode_t *
opl_node_create(topo_mod_t * mp,tnode_t * parent,const char * name,int inst,void * priv)66 opl_node_create(topo_mod_t *mp, tnode_t *parent, const char *name, int inst,
67     void *priv)
68 {
69 	tnode_t *node;
70 	nvlist_t *fmri;
71 	nvlist_t *auth = topo_mod_auth(mp, parent);
72 
73 	if (parent == NULL || inst < 0) {
74 		return (NULL);
75 	}
76 
77 	/* Create FMRI */
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)));
82 		nvlist_free(auth);
83 		return (NULL);
84 	}
85 	nvlist_free(auth);
86 
87 	/* Create and bind node  */
88 	node = topo_node_bind(mp, parent, name, inst, fmri);
89 	if (node == NULL) {
90 		nvlist_free(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 */
94 	}
95 
96 	nvlist_free(fmri);
97 	topo_node_setspecific(node, priv);
98 
99 	return (node);
100 }
101 
102 /*
103  * Create a root complex node.
104  */
105 static tnode_t *
opl_rc_node_create(topo_mod_t * mp,tnode_t * parent,di_node_t dnode,int inst)106 opl_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode, int inst)
107 {
108 	int err;
109 	tnode_t *rcn;
110 	const char *slot_name;
111 	char *dnpath;
112 	nvlist_t *mod;
113 
114 	rcn = opl_node_create(mp, parent, PCIEX_ROOT, inst, (void *)dnode);
115 	if (rcn == NULL) {
116 		return (NULL);
117 	}
118 
119 	/*
120 	 * If this root complex connects to a slot, it will have a
121 	 * slot-names property.
122 	 */
123 	slot_name = opl_get_slot_name(mp, dnode);
124 	if (slot_name) {
125 		char fru_str[64];
126 		nvlist_t *fru_fmri;
127 		/* Add FRU fmri */
128 		(void) snprintf(fru_str, sizeof (fru_str), "hc:///component=%s",
129 		    slot_name);
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);
133 		}
134 		/* Add label */
135 		(void) topo_node_label_set(rcn, (char *)slot_name, &err);
136 	} else {
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);
140 	}
141 
142 	/*
143 	 * Set ASRU to be the dev-scheme ASRU
144 	 */
145 	if ((dnpath = di_devfs_path(dnode)) != NULL) {
146 		nvlist_t *fmri;
147 
148 		fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
149 		    dnpath, NULL);
150 		if (fmri == NULL) {
151 			topo_mod_dprintf(mp,
152 			    "dev:///%s fmri creation failed.\n",
153 			    dnpath);
154 			(void) topo_mod_seterrno(mp, err);
155 			di_devfs_path_free(dnpath);
156 			return (NULL);
157 		}
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);
161 			nvlist_free(fmri);
162 			di_devfs_path_free(dnpath);
163 			return (NULL);
164 		}
165 		nvlist_free(fmri);
166 	} else {
167 		topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
168 	}
169 
170 	/*
171 	 * Set pciexrc properties for root complex nodes
172 	 */
173 
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);
179 		return (NULL);
180 	}
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);
185 		return (NULL);
186 	}
187 	/* Add the devfs path property */
188 	if (dnpath) {
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);
194 		}
195 		di_devfs_path_free(dnpath);
196 	}
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");
201 	}
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");
206 	}
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");
211 	}
212 	if (mod != NULL)
213 		nvlist_free(mod);
214 
215 	/* This is a PCIEX Root Complex */
216 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP,
217 	    TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) {
218 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
219 	}
220 	/* BDF of Oberon root complex is constant */
221 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI,
222 	    TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, OPL_PX_BDF, &err) != 0) {
223 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
224 	}
225 
226 	/* Make room for children */
227 	(void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, OPL_BUS_MAX);
228 	return (rcn);
229 }
230 
231 /*
232  * Create a hostbridge node.
233  */
234 static tnode_t *
opl_hb_node_create(topo_mod_t * mp,tnode_t * parent,int inst)235 opl_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst)
236 {
237 	int err;
238 	tnode_t *hbn;
239 
240 	hbn = opl_node_create(mp, parent, HOSTBRIDGE, inst, NULL);
241 	if (hbn == NULL) {
242 		return (NULL);
243 	}
244 
245 	/* Inherit parent FRU's label */
246 	(void) topo_node_fru_set(hbn, NULL, 0, &err);
247 	(void) topo_node_label_set(hbn, NULL, &err);
248 
249 	/* Make room for children */
250 	(void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, OPL_RC_MAX);
251 
252 	return (hbn);
253 }
254 
255 /*
256  * opl_hb_enum gets the ioboard instance passed in, and determines the
257  * hostbridge and root complex instances numbers based on the bus addresses.
258  */
259 int
opl_hb_enum(topo_mod_t * mp,const ioboard_contents_t * iob,tnode_t * ion,int brd)260 opl_hb_enum(topo_mod_t *mp, const ioboard_contents_t *iob, tnode_t *ion,
261     int brd)
262 {
263 	int hb;
264 	int rc;
265 	di_node_t p;
266 	tnode_t *hbnode;
267 	tnode_t *rcnode;
268 	topo_mod_t *pcimod;
269 
270 	/* Load the pcibus module. We'll need it later. */
271 	pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS);
272 	if (pcimod == NULL) {
273 		topo_mod_dprintf(mp, "can't load pcibus module: %s\n",
274 		    topo_strerror(topo_mod_errno(mp)));
275 		return (-1);
276 	}
277 
278 	/* For each hostbridge on an ioboard... */
279 	for (hb = 0; hb < OPL_HB_MAX; hb++) {
280 		hbnode = NULL;
281 		/* For each root complex in a hostbridge... */
282 		for (rc = 0; rc < OPL_RC_MAX; rc++) {
283 			p = iob->rcs[hb][rc];
284 			/* If no root complex, continue */
285 			if (p == DI_NODE_NIL) {
286 				continue;
287 			}
288 
289 			/* The root complex exists! */
290 			topo_mod_dprintf(mp, "declaring "
291 			    "/chassis=0/ioboard=%d/hostbridge=%d/pciexrc=%d\n",
292 			    brd, hb, rc);
293 
294 			/*
295 			 * If we haven't created a hostbridge node yet, do it
296 			 * now.
297 			 */
298 			if (hbnode == NULL) {
299 				hbnode = opl_hb_node_create(mp, ion, hb);
300 				if (hbnode == NULL) {
301 					topo_mod_dprintf(mp,
302 					    "unable to create hbnode: %s\n",
303 					    topo_strerror(topo_mod_errno(mp)));
304 					topo_mod_unload(pcimod);
305 					return (-1);
306 				}
307 
308 			}
309 
310 			/* Create the root complex node */
311 			rcnode = opl_rc_node_create(mp, hbnode, p, rc);
312 			if (rcnode == NULL) {
313 				topo_mod_dprintf(mp,
314 				    "unable to create rcnode: %s\n",
315 				    topo_strerror(topo_mod_errno(mp)));
316 				topo_mod_unload(pcimod);
317 				return (-1);
318 			}
319 
320 			/* Enumerate pcibus nodes under the root complex */
321 			if (topo_mod_enumerate(pcimod, rcnode,
322 			    PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) {
323 				topo_mod_dprintf(mp,
324 				    "error enumerating pcibus: %s\n",
325 				    topo_strerror(topo_mod_errno(mp)));
326 				topo_mod_unload(pcimod);
327 				return (-1);
328 			}
329 		}
330 	}
331 	topo_mod_unload(pcimod);
332 	return (0);
333 }
334