xref: /titanic_44/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.c (revision 12cc75c814f0c017004a9bbc96429911e008601b)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <string.h>
30 #include <fm/topo_mod.h>
31 #include <libdevinfo.h>
32 #include <sys/param.h>
33 #include <sys/systeminfo.h>
34 
35 #include <hb_sun4.h>
36 #include <util.h>
37 #include <hostbridge.h>
38 #include <pcibus.h>
39 #include <did.h>
40 
41 busorrc_t *
busorrc_new(topo_mod_t * mod,const char * bus_addr,di_node_t di)42 busorrc_new(topo_mod_t *mod, const char *bus_addr, di_node_t di)
43 {
44 	busorrc_t *pp;
45 	char *comma;
46 	char *bac;
47 	int e;
48 
49 	if ((pp = topo_mod_zalloc(mod, sizeof (busorrc_t))) == NULL)
50 		return (NULL);
51 	pp->br_din = di;
52 	bac = topo_mod_strdup(mod, bus_addr);
53 	if ((comma = strchr(bac, ',')) != NULL)
54 		*comma = '\0';
55 	pp->br_ba_bc = strtonum(mod, bac, &e);
56 	if (e < 0) {
57 		topo_mod_dprintf(mod,
58 		    "Trouble interpreting bus_addr before comma.\n");
59 		if (comma != NULL)
60 			*comma = ',';
61 		topo_mod_strfree(mod, bac);
62 		topo_mod_free(mod, pp, sizeof (busorrc_t));
63 		return (NULL);
64 	}
65 	if (comma == NULL) {
66 		pp->br_ba_ac = 0;
67 		topo_mod_strfree(mod, bac);
68 		return (pp);
69 	}
70 	pp->br_ba_ac = strtonum(mod, comma + 1, &e);
71 	if (e < 0) {
72 		topo_mod_dprintf(mod,
73 		    "Trouble interpreting bus_addr after comma.\n");
74 		*comma = ',';
75 		topo_mod_strfree(mod, bac);
76 		topo_mod_free(mod, pp, sizeof (busorrc_t));
77 		return (NULL);
78 	}
79 	*comma = ',';
80 	topo_mod_strfree(mod, bac);
81 	return (pp);
82 }
83 
84 void
busorrc_insert(topo_mod_t * mod,busorrc_t ** head,busorrc_t * new)85 busorrc_insert(topo_mod_t *mod, busorrc_t **head, busorrc_t *new)
86 {
87 	busorrc_t *ppci, *pci;
88 
89 	topo_mod_dprintf(mod,
90 	    "inserting (%x,%x)\n", new->br_ba_bc, new->br_ba_ac);
91 
92 	/* No entries yet? */
93 	if (*head == NULL) {
94 		*head = new;
95 		return;
96 	}
97 
98 	ppci = NULL;
99 	pci = *head;
100 
101 	while (pci != NULL) {
102 		if (new->br_ba_ac == pci->br_ba_ac)
103 			if (new->br_ba_bc < pci->br_ba_bc)
104 				break;
105 		if (new->br_ba_ac < pci->br_ba_ac)
106 			break;
107 		ppci = pci;
108 		pci = pci->br_nextbus;
109 	}
110 	if (ppci == NULL) {
111 		new->br_nextbus = pci;
112 		pci->br_prevbus = new;
113 		*head = new;
114 	} else {
115 		new->br_nextbus = ppci->br_nextbus;
116 		if (new->br_nextbus != NULL)
117 			new->br_nextbus->br_prevbus = new;
118 		ppci->br_nextbus = new;
119 		new->br_prevbus = ppci;
120 	}
121 }
122 
123 int
busorrc_add(topo_mod_t * mod,busorrc_t ** list,di_node_t n)124 busorrc_add(topo_mod_t *mod, busorrc_t **list, di_node_t n)
125 {
126 	busorrc_t *nb;
127 	char *ba;
128 
129 	topo_mod_dprintf(mod, "busorrc_add\n");
130 	ba = di_bus_addr(n);
131 	if (ba == NULL ||
132 	    (nb = busorrc_new(mod, ba, n)) == NULL) {
133 		topo_mod_dprintf(mod, "busorrc_new() failed.\n");
134 		return (-1);
135 	}
136 	busorrc_insert(mod, list, nb);
137 	return (0);
138 }
139 
140 void
busorrc_free(topo_mod_t * mod,busorrc_t * pb)141 busorrc_free(topo_mod_t *mod, busorrc_t *pb)
142 {
143 	if (pb == NULL)
144 		return;
145 	busorrc_free(mod, pb->br_nextbus);
146 	topo_mod_free(mod, pb, sizeof (busorrc_t));
147 }
148 
149 tnode_t *
hb_process(topo_mod_t * mod,tnode_t * ptn,topo_instance_t hbi,topo_instance_t bi,di_node_t bn,did_t * hbdid)150 hb_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t hbi,
151     topo_instance_t bi, di_node_t bn, did_t *hbdid)
152 {
153 	tnode_t *hb;
154 
155 	if ((hb = pcihostbridge_declare(mod, ptn, bn, hbi)) == NULL)
156 		return (NULL);
157 	if (topo_mod_enumerate(mod, hb, PCI_BUS, PCI_BUS, bi, bi, hbdid) == 0)
158 		return (hb);
159 
160 	topo_node_unbind(hb);
161 
162 	return (NULL);
163 }
164 
165 tnode_t *
rc_process(topo_mod_t * mod,tnode_t * ptn,topo_instance_t rci,di_node_t bn)166 rc_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t rci, di_node_t bn)
167 {
168 	tnode_t *rc;
169 
170 	if ((rc = pciexrc_declare(mod, ptn, bn, rci)) == NULL)
171 		return (NULL);
172 	if (topo_mod_enumerate(mod,
173 	    rc, PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES, NULL) == 0)
174 		return (rc);
175 
176 	topo_node_unbind(rc);
177 
178 	return (NULL);
179 }
180 
181 /*
182  * declare_exbuses() assumes the elements in the provided busorrc list
183  * are sorted thusly:
184  *
185  *	(Hostbridge #0, Root Complex #0, ExBus #0)
186  *	(Hostbridge #0, Root Complex #0, ExBus #1)
187  *		...
188  *	(Hostbridge #0, Root Complex #0, ExBus #(buses/rc))
189  *	(Hostbridge #0, Root Complex #1, ExBus #0)
190  *		...
191  *	(Hostbridge #0, Root Complex #1, ExBus #(buses/rc))
192  *		...
193  *		...
194  *	(Hostbridge #0, Root Complex #(rcs/hostbridge), ExBus #(buses/rc))
195  *	(Hostbridge #1, Root Complex #0, ExBus #0)
196  *		...
197  *		...
198  *		...
199  *		...
200  *	(Hostbridge #nhb, Root Complex #(rcs/hostbridge), ExBus #(buses/rc))
201  */
202 int
declare_exbuses(topo_mod_t * mod,busorrc_t * list,tnode_t * ptn,int nhb,int nrc)203 declare_exbuses(topo_mod_t *mod, busorrc_t *list, tnode_t *ptn, int nhb,
204     int nrc)
205 {
206 	int err = 0;
207 	tnode_t **rcs;
208 	tnode_t **hb;
209 	busorrc_t *p;
210 	int br, rc;
211 
212 	/*
213 	 * Allocate an array to point at the hostbridge tnode_t pointers.
214 	 */
215 	if ((hb = topo_mod_zalloc(mod, nhb * sizeof (tnode_t *))) == NULL)
216 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
217 
218 	/*
219 	 * Allocate an array to point at the root complex tnode_t pointers.
220 	 */
221 	if ((rcs = topo_mod_zalloc(mod, nrc * sizeof (tnode_t *))) == NULL) {
222 		topo_mod_free(mod, hb, nhb * sizeof (tnode_t *));
223 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
224 	}
225 
226 	br = rc = 0;
227 	for (p = list; p != NULL; p = p->br_nextbus) {
228 		topo_mod_dprintf(mod,
229 		    "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac);
230 
231 		if (did_create(mod, p->br_din, 0, br, rc, rc) == NULL) {
232 			err = -1;
233 			break;
234 		}
235 
236 		if (hb[br] == NULL) {
237 			hb[br] = pciexhostbridge_declare(mod, ptn, p->br_din,
238 			    br);
239 			if (hb[br] == NULL) {
240 				err = -1;
241 				break;
242 			}
243 		}
244 		if (rcs[rc] == NULL) {
245 			rcs[rc] = rc_process(mod, hb[br], rc, p->br_din);
246 			if (rcs[rc] == NULL) {
247 				err = -1;
248 				break;
249 			}
250 		} else {
251 			if (topo_mod_enumerate(mod,
252 			    rcs[rc], PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES,
253 			    NULL) < 0) {
254 				err = -1;
255 				break;
256 			}
257 		}
258 		rc++;
259 		if (rc == nrc) {
260 			rc = 0;
261 			br++;
262 			if (br == nhb)
263 				br = 0;
264 		}
265 	}
266 
267 	if (err != 0) {
268 		int i;
269 
270 		for (i = 0; i < nhb; ++i)
271 			topo_node_unbind(hb[br]);
272 		for (i = 0; i < nrc; ++i)
273 			topo_node_unbind(rcs[rc]);
274 	}
275 
276 	topo_mod_free(mod, rcs, nrc * sizeof (tnode_t *));
277 	topo_mod_free(mod, hb, nhb * sizeof (tnode_t *));
278 
279 	return (err);
280 }
281 
282 /*
283  * declare_buses() assumes the elements in the provided busorrc list
284  * are sorted thusly:
285  *
286  *	(Hostbridge #0, Bus #0)
287  *	(Hostbridge #1, Bus #0)
288  *		...
289  *	(Hostbridge #nhb, Bus #0)
290  *	(Hostbridge #0, Bus #1)
291  *		...
292  *		...
293  *	(Hostbridge #nhb, Bus #(buses/hostbridge))
294  */
295 int
declare_buses(topo_mod_t * mod,busorrc_t * list,tnode_t * ptn,int nhb)296 declare_buses(topo_mod_t *mod, busorrc_t *list, tnode_t *ptn, int nhb)
297 {
298 	int err = 0;
299 	busorrc_t *p;
300 	tnode_t **hb;
301 	did_t *link;
302 	int br, bus;
303 
304 	/*
305 	 * Allocate an array to point at the hostbridge tnode_t pointers.
306 	 */
307 	if ((hb = topo_mod_zalloc(mod, nhb * sizeof (tnode_t *))) == NULL)
308 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
309 
310 	br = bus = 0;
311 	for (p = list; p != NULL; p = p->br_nextbus) {
312 		topo_mod_dprintf(mod,
313 		    "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac);
314 
315 		if ((link =
316 		    did_create(mod, p->br_din, 0, br, NO_RC, bus)) == NULL) {
317 			err = -1;
318 			break;
319 		}
320 
321 		if (hb[br] == NULL) {
322 			hb[br] = hb_process(mod, ptn, br, bus, p->br_din, link);
323 			if (hb[br] == NULL) {
324 				err = -1;
325 				break;
326 			}
327 		} else {
328 			did_link_set(mod, hb[br], link);
329 			if (topo_mod_enumerate(mod,
330 			    hb[br], PCI_BUS, PCI_BUS, bus, bus, link) < 0) {
331 				err = -1;
332 				break;
333 			}
334 		}
335 		br++;
336 		if (br == nhb) {
337 			br = 0;
338 			bus++;
339 		}
340 	}
341 
342 	if (err != 0) {
343 		int i;
344 
345 		for (i = 0; i < nhb; ++i)
346 			topo_node_unbind(hb[br]);
347 	}
348 
349 	topo_mod_free(mod, hb, nhb * sizeof (tnode_t *));
350 	return (err);
351 }
352