xref: /titanic_41/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_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 "cpuboard_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 static tnode_t *
cpuboard_node_create(topo_mod_t * mp,tnode_t * parent,const char * name,int inst,void * priv)41 cpuboard_node_create(topo_mod_t *mp, tnode_t *parent, const char *name,
42     int inst, void *priv)
43 {
44 	tnode_t *node;
45 	nvlist_t *fmri;
46 	nvlist_t *auth = topo_mod_auth(mp, parent);
47 
48 	topo_mod_dprintf(mp, "cpuboard_node_create:\n");
49 
50 	if (parent == NULL || inst < 0) {
51 		return (NULL);
52 	}
53 
54 	/* Create FMRI */
55 	if ((fmri = topo_mod_hcfmri(mp, parent, FM_HC_SCHEME_VERSION, name,
56 	    inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
57 		topo_mod_dprintf(mp, "create of tnode for %s failed: %s",
58 		    name, topo_strerror(topo_mod_errno(mp)));
59 		nvlist_free(auth);
60 		return (NULL);
61 	}
62 	nvlist_free(auth);
63 
64 	/* Create and bind node  */
65 	node = topo_node_bind(mp, parent, name, inst, fmri);
66 	if (node == NULL) {
67 		nvlist_free(fmri);
68 		topo_mod_dprintf(mp, "unable to bind root complex: %s\n",
69 		    topo_strerror(topo_mod_errno(mp)));
70 		return (NULL); /* mod_errno already set */
71 	}
72 
73 	nvlist_free(fmri);
74 	topo_node_setspecific(node, priv);
75 
76 	return (node);
77 }
78 
79 /*
80  * cpuboard_rc_node_create()
81  * Description:
82  *     Create a root complex node pciexrc
83  * Parameters:
84  *     mp: topo module pointer
85  *     parent: topo parent node of the newly created pciexrc node
86  *     dnode: Solaris device node of the root complex
87  *     rcpath: Used to populated the dev property of the topo pciexrc node if
88  *          the local host does not own the root complex.
89  */
90 static tnode_t *
cpuboard_rc_node_create(topo_mod_t * mp,tnode_t * parent,di_node_t dnode,char * rcpath,int inst)91 cpuboard_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode,
92     char *rcpath, int inst)
93 {
94 	int err;
95 	tnode_t *rcn;
96 	char *dnpath;
97 	nvlist_t *mod;
98 
99 	topo_mod_dprintf(mp, "cpuboard_rc_node_create:\n");
100 
101 	rcn = cpuboard_node_create(mp, parent, PCIEX_ROOT, inst, (void *)dnode);
102 	if (rcn == NULL) {
103 		return (NULL);
104 	}
105 
106 	/* Inherit parent FRU's label */
107 	(void) topo_node_fru_set(rcn, NULL, 0, &err);
108 	(void) topo_node_label_set(rcn, NULL, &err);
109 
110 	/*
111 	 * Set ASRU to be the dev-scheme ASRU
112 	 */
113 	if ((dnpath = di_devfs_path(dnode)) != NULL) {
114 		nvlist_t *fmri;
115 
116 		/*
117 		 * The local host owns the root complex, so use the dev path
118 		 * from the di_devfs_path(), instead of the passed in rcpath,
119 		 * to populate the dev property.
120 		 */
121 		rcpath = dnpath;
122 		fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
123 		    dnpath, NULL);
124 		if (fmri == NULL) {
125 			topo_mod_dprintf(mp,
126 			    "dev:///%s fmri creation failed.\n",
127 			    dnpath);
128 			(void) topo_mod_seterrno(mp, err);
129 			di_devfs_path_free(dnpath);
130 			return (NULL);
131 		}
132 		if (topo_node_asru_set(rcn, fmri, 0, &err) < 0) {
133 			topo_mod_dprintf(mp, "topo_node_asru_set failed\n");
134 			(void) topo_mod_seterrno(mp, err);
135 			nvlist_free(fmri);
136 			di_devfs_path_free(dnpath);
137 			return (NULL);
138 		}
139 		nvlist_free(fmri);
140 	} else {
141 		topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
142 	}
143 
144 	/*
145 	 * Set pciexrc properties for root complex nodes
146 	 */
147 
148 	/* Add the io and pci property groups */
149 	if (topo_pgroup_create(rcn, &io_pgroup, &err) < 0) {
150 		topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
151 		di_devfs_path_free(dnpath);
152 		(void) topo_mod_seterrno(mp, err);
153 		return (NULL);
154 	}
155 	if (topo_pgroup_create(rcn, &pci_pgroup, &err) < 0) {
156 		topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
157 		di_devfs_path_free(dnpath);
158 		(void) topo_mod_seterrno(mp, err);
159 		return (NULL);
160 	}
161 	/* Add the devfs path property */
162 	if (rcpath) {
163 		if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEV,
164 		    TOPO_PROP_IMMUTABLE, rcpath, &err) != 0) {
165 			topo_mod_dprintf(mp, "Failed to set DEV property\n");
166 			(void) topo_mod_seterrno(mp, err);
167 		}
168 	}
169 	if (dnpath) {
170 		di_devfs_path_free(dnpath);
171 	}
172 	/* T5440 device type is always "pciex" */
173 	if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE,
174 	    TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DEVTYPE, &err) != 0) {
175 		topo_mod_dprintf(mp, "Failed to set DEVTYPE property\n");
176 	}
177 	/* T5440 driver is always "px" */
178 	if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
179 	    TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DRV, &err) != 0) {
180 		topo_mod_dprintf(mp, "Failed to set DRIVER property\n");
181 	}
182 	if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, CPUBOARD_PX_DRV))
183 	    == NULL || topo_prop_set_fmri(rcn, TOPO_PGROUP_IO,
184 	    TOPO_IO_MODULE, TOPO_PROP_IMMUTABLE, mod,  &err) != 0) {
185 		topo_mod_dprintf(mp, "Failed to set MODULE property\n");
186 	}
187 	if (mod != NULL)
188 		nvlist_free(mod);
189 
190 	/* This is a PCIEX Root Complex */
191 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP,
192 	    TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) {
193 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
194 	}
195 	/* BDF of T5440 root complex is constant */
196 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI,
197 	    TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, CPUBOARD_PX_BDF, &err) != 0) {
198 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
199 	}
200 
201 	/* Make room for children */
202 	(void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, CPUBOARD_MAX);
203 	return (rcn);
204 }
205 
206 /*
207  * Create a hostbridge node.
208  */
209 static tnode_t *
cpuboard_hb_node_create(topo_mod_t * mp,tnode_t * parent,int inst)210 cpuboard_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst)
211 {
212 	int err;
213 	tnode_t *hbn;
214 
215 	topo_mod_dprintf(mp, "cpuboard_hb_node_create: parent=%p, inst=%d\n",
216 	    parent, inst);
217 
218 	hbn = cpuboard_node_create(mp, parent, HOSTBRIDGE, inst, NULL);
219 	if (hbn == NULL) {
220 		topo_mod_dprintf(mp, "cpuboard_hb_node_create: "
221 		    "cpuboard_node_create() failed.\n");
222 		return (NULL);
223 	}
224 
225 	/* Inherit parent FRU's label */
226 	(void) topo_node_fru_set(hbn, NULL, 0, &err);
227 	(void) topo_node_label_set(hbn, NULL, &err);
228 
229 	/* Make room for children */
230 	(void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, CPUBOARD_MAX);
231 
232 	topo_mod_dprintf(mp, "cpuboard_hb_node_create: EXIT hbn=%p\n", hbn);
233 
234 	return (hbn);
235 }
236 
237 /*
238  * Enumerate hostbridge on the cpuboard.  Hostbridge and root complex instances
239  * match the cpuboard instance.
240  */
241 int
cpuboard_hb_enum(topo_mod_t * mp,di_node_t dnode,char * rcpath,tnode_t * cpubn,int brd)242 cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, char *rcpath,
243     tnode_t *cpubn, int brd)
244 {
245 	int hb;
246 	int rc;
247 	tnode_t *hbnode;
248 	tnode_t *rcnode;
249 	topo_mod_t *pcimod;
250 
251 	topo_mod_dprintf(mp, "cpuboard_hb_enum: brd: %d, cpubn=%p\n",
252 	    brd, cpubn);
253 
254 	/* Load the pcibus module. We'll need it later. */
255 	pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS);
256 	if (pcimod == NULL) {
257 		topo_mod_dprintf(mp, "can't load pcibus module: %s\n",
258 		    topo_strerror(topo_mod_errno(mp)));
259 		return (-1);
260 	}
261 	hb = rc = brd;
262 
263 	/* The root complex exists! */
264 	topo_mod_dprintf(mp, "declaring "
265 	    "/motherboard=0/cpuboard=%d/hostbridge=%d/"
266 	    "pciexrc=%d\n", brd, hb, rc);
267 
268 	/* Create the hostbridge node */
269 	hbnode = cpuboard_hb_node_create(mp, cpubn, hb);
270 	if (hbnode == NULL) {
271 		topo_mod_dprintf(mp,
272 		    "unable to create hbnode: %s\n",
273 		    topo_strerror(topo_mod_errno(mp)));
274 		topo_mod_unload(pcimod);
275 		return (-1);
276 	}
277 	/* Create the root complex node */
278 	rcnode = cpuboard_rc_node_create(mp, hbnode, dnode, rcpath, rc);
279 	if (rcnode == NULL) {
280 		topo_mod_dprintf(mp,
281 		    "unable to create rcnode: %s\n",
282 		    topo_strerror(topo_mod_errno(mp)));
283 		topo_mod_unload(pcimod);
284 		return (-1);
285 	}
286 	/*
287 	 * If dnode not NULL, enumerate pcibus nodes under the root complex.
288 	 * If dnode NULL, skip enumeration.  Condition could occur if the RC
289 	 * is assigned to non-control domain.
290 	 */
291 	if ((dnode != NULL) && topo_mod_enumerate(pcimod, rcnode,
292 	    PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) {
293 		topo_mod_dprintf(mp,
294 		    "error enumerating pcibus: %s\n",
295 		    topo_strerror(topo_mod_errno(mp)));
296 		topo_mod_unload(pcimod);
297 		return (-1);
298 	}
299 	topo_mod_unload(pcimod);
300 	return (0);
301 }
302