xref: /onnv-gate/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.c (revision 4328:fe6ac87d8e60)
11414Scindi /*
21414Scindi  * CDDL HEADER START
31414Scindi  *
41414Scindi  * The contents of this file are subject to the terms of the
51414Scindi  * Common Development and Distribution License (the "License").
61414Scindi  * You may not use this file except in compliance with the License.
71414Scindi  *
81414Scindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91414Scindi  * or http://www.opensolaris.org/os/licensing.
101414Scindi  * See the License for the specific language governing permissions
111414Scindi  * and limitations under the License.
121414Scindi  *
131414Scindi  * When distributing Covered Code, include this CDDL HEADER in each
141414Scindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151414Scindi  * If applicable, add the following below this CDDL HEADER, with the
161414Scindi  * fields enclosed by brackets "[]" replaced with your own identifying
171414Scindi  * information: Portions Copyright [yyyy] [name of copyright owner]
181414Scindi  *
191414Scindi  * CDDL HEADER END
201414Scindi  */
211414Scindi 
221414Scindi /*
23*4328Scindi  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241414Scindi  * Use is subject to license terms.
251414Scindi  */
261414Scindi 
271414Scindi #pragma ident	"%Z%%M%	%I%	%E% SMI"
281414Scindi 
291414Scindi #include <string.h>
301414Scindi #include <fm/topo_mod.h>
311414Scindi #include <libdevinfo.h>
321414Scindi #include <sys/param.h>
331414Scindi #include <sys/systeminfo.h>
341414Scindi 
353062Scindi #include <hb_sun4.h>
363062Scindi #include <util.h>
373062Scindi #include <hostbridge.h>
383062Scindi #include <pcibus.h>
393062Scindi #include <did.h>
401414Scindi 
411414Scindi busorrc_t *
busorrc_new(topo_mod_t * mod,const char * bus_addr,di_node_t di)423062Scindi busorrc_new(topo_mod_t *mod, const char *bus_addr, di_node_t di)
431414Scindi {
441414Scindi 	busorrc_t *pp;
451414Scindi 	char *comma;
461414Scindi 	char *bac;
471414Scindi 	int e;
481414Scindi 
492027Ssethg 	if ((pp = topo_mod_zalloc(mod, sizeof (busorrc_t))) == NULL)
501414Scindi 		return (NULL);
511414Scindi 	pp->br_din = di;
522027Ssethg 	bac = topo_mod_strdup(mod, bus_addr);
531414Scindi 	if ((comma = strchr(bac, ',')) != NULL)
541414Scindi 		*comma = '\0';
552027Ssethg 	pp->br_ba_bc = strtonum(mod, bac, &e);
561414Scindi 	if (e < 0) {
572027Ssethg 		topo_mod_dprintf(mod,
581414Scindi 		    "Trouble interpreting bus_addr before comma.\n");
591414Scindi 		if (comma != NULL)
601414Scindi 			*comma = ',';
612027Ssethg 		topo_mod_strfree(mod, bac);
622027Ssethg 		topo_mod_free(mod, pp, sizeof (busorrc_t));
631414Scindi 		return (NULL);
641414Scindi 	}
651414Scindi 	if (comma == NULL) {
661414Scindi 		pp->br_ba_ac = 0;
672027Ssethg 		topo_mod_strfree(mod, bac);
681414Scindi 		return (pp);
691414Scindi 	}
702027Ssethg 	pp->br_ba_ac = strtonum(mod, comma + 1, &e);
711414Scindi 	if (e < 0) {
722027Ssethg 		topo_mod_dprintf(mod,
731414Scindi 		    "Trouble interpreting bus_addr after comma.\n");
741414Scindi 		*comma = ',';
752027Ssethg 		topo_mod_strfree(mod, bac);
762027Ssethg 		topo_mod_free(mod, pp, sizeof (busorrc_t));
771414Scindi 		return (NULL);
781414Scindi 	}
791414Scindi 	*comma = ',';
802027Ssethg 	topo_mod_strfree(mod, bac);
811414Scindi 	return (pp);
821414Scindi }
831414Scindi 
841414Scindi void
busorrc_insert(topo_mod_t * mod,busorrc_t ** head,busorrc_t * new)853062Scindi busorrc_insert(topo_mod_t *mod, busorrc_t **head, busorrc_t *new)
861414Scindi {
871414Scindi 	busorrc_t *ppci, *pci;
881414Scindi 
892027Ssethg 	topo_mod_dprintf(mod,
901414Scindi 	    "inserting (%x,%x)\n", new->br_ba_bc, new->br_ba_ac);
911414Scindi 
921414Scindi 	/* No entries yet? */
931414Scindi 	if (*head == NULL) {
941414Scindi 		*head = new;
951414Scindi 		return;
961414Scindi 	}
971414Scindi 
981414Scindi 	ppci = NULL;
991414Scindi 	pci = *head;
1001414Scindi 
1011414Scindi 	while (pci != NULL) {
1021414Scindi 		if (new->br_ba_ac == pci->br_ba_ac)
1031414Scindi 			if (new->br_ba_bc < pci->br_ba_bc)
1041414Scindi 				break;
1051414Scindi 		if (new->br_ba_ac < pci->br_ba_ac)
1061414Scindi 			break;
1071414Scindi 		ppci = pci;
1081414Scindi 		pci = pci->br_nextbus;
1091414Scindi 	}
1101414Scindi 	if (ppci == NULL) {
1111414Scindi 		new->br_nextbus = pci;
1121414Scindi 		pci->br_prevbus = new;
1131414Scindi 		*head = new;
1141414Scindi 	} else {
1151414Scindi 		new->br_nextbus = ppci->br_nextbus;
1161414Scindi 		if (new->br_nextbus != NULL)
1171414Scindi 			new->br_nextbus->br_prevbus = new;
1181414Scindi 		ppci->br_nextbus = new;
1191414Scindi 		new->br_prevbus = ppci;
1201414Scindi 	}
1211414Scindi }
1221414Scindi 
1231414Scindi int
busorrc_add(topo_mod_t * mod,busorrc_t ** list,di_node_t n)1243062Scindi busorrc_add(topo_mod_t *mod, busorrc_t **list, di_node_t n)
1251414Scindi {
1261414Scindi 	busorrc_t *nb;
1271414Scindi 	char *ba;
1281414Scindi 
1292027Ssethg 	topo_mod_dprintf(mod, "busorrc_add\n");
1301414Scindi 	ba = di_bus_addr(n);
1311414Scindi 	if (ba == NULL ||
1323062Scindi 	    (nb = busorrc_new(mod, ba, n)) == NULL) {
1332027Ssethg 		topo_mod_dprintf(mod, "busorrc_new() failed.\n");
1341414Scindi 		return (-1);
1351414Scindi 	}
1363062Scindi 	busorrc_insert(mod, list, nb);
1371414Scindi 	return (0);
1381414Scindi }
1391414Scindi 
1401414Scindi void
busorrc_free(topo_mod_t * mod,busorrc_t * pb)1413062Scindi busorrc_free(topo_mod_t *mod, busorrc_t *pb)
1421414Scindi {
1431414Scindi 	if (pb == NULL)
1441414Scindi 		return;
1453062Scindi 	busorrc_free(mod, pb->br_nextbus);
1462027Ssethg 	topo_mod_free(mod, pb, sizeof (busorrc_t));
1471414Scindi }
1481414Scindi 
1491414Scindi 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)1503062Scindi hb_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t hbi,
1513062Scindi     topo_instance_t bi, di_node_t bn, did_t *hbdid)
1521414Scindi {
1531414Scindi 	tnode_t *hb;
1541414Scindi 
1553062Scindi 	if ((hb = pcihostbridge_declare(mod, ptn, bn, hbi)) == NULL)
1561414Scindi 		return (NULL);
1573062Scindi 	if (topo_mod_enumerate(mod, hb, PCI_BUS, PCI_BUS, bi, bi, hbdid) == 0)
1581414Scindi 		return (hb);
159*4328Scindi 
160*4328Scindi 	topo_node_unbind(hb);
161*4328Scindi 
1621414Scindi 	return (NULL);
1631414Scindi }
1641414Scindi 
1651414Scindi tnode_t *
rc_process(topo_mod_t * mod,tnode_t * ptn,topo_instance_t rci,di_node_t bn)1663062Scindi rc_process(topo_mod_t *mod, tnode_t *ptn, topo_instance_t rci, di_node_t bn)
1671414Scindi {
1681414Scindi 	tnode_t *rc;
1691414Scindi 
1703062Scindi 	if ((rc = pciexrc_declare(mod, ptn, bn, rci)) == NULL)
1711414Scindi 		return (NULL);
1722027Ssethg 	if (topo_mod_enumerate(mod,
1733062Scindi 	    rc, PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES, NULL) == 0)
1741414Scindi 		return (rc);
175*4328Scindi 
176*4328Scindi 	topo_node_unbind(rc);
177*4328Scindi 
1781414Scindi 	return (NULL);
1791414Scindi }
1801414Scindi 
1811414Scindi /*
1821414Scindi  * declare_exbuses() assumes the elements in the provided busorrc list
1831414Scindi  * are sorted thusly:
1841414Scindi  *
1851414Scindi  *	(Hostbridge #0, Root Complex #0, ExBus #0)
1861414Scindi  *	(Hostbridge #0, Root Complex #0, ExBus #1)
1871414Scindi  *		...
1881414Scindi  *	(Hostbridge #0, Root Complex #0, ExBus #(buses/rc))
1891414Scindi  *	(Hostbridge #0, Root Complex #1, ExBus #0)
1901414Scindi  *		...
1911414Scindi  *	(Hostbridge #0, Root Complex #1, ExBus #(buses/rc))
1921414Scindi  *		...
1931414Scindi  *		...
1941414Scindi  *	(Hostbridge #0, Root Complex #(rcs/hostbridge), ExBus #(buses/rc))
1951414Scindi  *	(Hostbridge #1, Root Complex #0, ExBus #0)
1961414Scindi  *		...
1971414Scindi  *		...
1981414Scindi  *		...
1991414Scindi  *		...
2001414Scindi  *	(Hostbridge #nhb, Root Complex #(rcs/hostbridge), ExBus #(buses/rc))
2011414Scindi  */
2021414Scindi int
declare_exbuses(topo_mod_t * mod,busorrc_t * list,tnode_t * ptn,int nhb,int nrc)2033062Scindi declare_exbuses(topo_mod_t *mod, busorrc_t *list, tnode_t *ptn, int nhb,
2043062Scindi     int nrc)
2051414Scindi {
206*4328Scindi 	int err = 0;
2071414Scindi 	tnode_t **rcs;
2081414Scindi 	tnode_t **hb;
2091414Scindi 	busorrc_t *p;
2101414Scindi 	int br, rc;
2111414Scindi 
2121414Scindi 	/*
2131414Scindi 	 * Allocate an array to point at the hostbridge tnode_t pointers.
2141414Scindi 	 */
2152027Ssethg 	if ((hb = topo_mod_zalloc(mod, nhb * sizeof (tnode_t *))) == NULL)
2163062Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2171414Scindi 
2181414Scindi 	/*
2191414Scindi 	 * Allocate an array to point at the root complex tnode_t pointers.
2201414Scindi 	 */
221*4328Scindi 	if ((rcs = topo_mod_zalloc(mod, nrc * sizeof (tnode_t *))) == NULL) {
222*4328Scindi 		topo_mod_free(mod, hb, nhb * sizeof (tnode_t *));
2233062Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
224*4328Scindi 	}
2251414Scindi 
2261414Scindi 	br = rc = 0;
2271414Scindi 	for (p = list; p != NULL; p = p->br_nextbus) {
2282027Ssethg 		topo_mod_dprintf(mod,
2291414Scindi 		    "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac);
2301414Scindi 
231*4328Scindi 		if (did_create(mod, p->br_din, 0, br, rc, rc) == NULL) {
232*4328Scindi 			err = -1;
233*4328Scindi 			break;
234*4328Scindi 		}
2351414Scindi 
2361414Scindi 		if (hb[br] == NULL) {
2373062Scindi 			hb[br] = pciexhostbridge_declare(mod, ptn, p->br_din,
2383062Scindi 			    br);
239*4328Scindi 			if (hb[br] == NULL) {
240*4328Scindi 				err = -1;
241*4328Scindi 				break;
242*4328Scindi 			}
2431414Scindi 		}
2441414Scindi 		if (rcs[rc] == NULL) {
2453062Scindi 			rcs[rc] = rc_process(mod, hb[br], rc, p->br_din);
246*4328Scindi 			if (rcs[rc] == NULL) {
247*4328Scindi 				err = -1;
248*4328Scindi 				break;
249*4328Scindi 			}
2501414Scindi 		} else {
2512027Ssethg 			if (topo_mod_enumerate(mod,
2523062Scindi 			    rcs[rc], PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES,
253*4328Scindi 			    NULL) < 0) {
254*4328Scindi 				err = -1;
255*4328Scindi 				break;
256*4328Scindi 			}
2571414Scindi 		}
2581414Scindi 		rc++;
2591414Scindi 		if (rc == nrc) {
2601414Scindi 			rc = 0;
2611414Scindi 			br++;
2621414Scindi 			if (br == nhb)
2631414Scindi 				br = 0;
2641414Scindi 		}
2651414Scindi 	}
266*4328Scindi 
267*4328Scindi 	if (err != 0) {
268*4328Scindi 		int i;
269*4328Scindi 
270*4328Scindi 		for (i = 0; i < nhb; ++i)
271*4328Scindi 			topo_node_unbind(hb[br]);
272*4328Scindi 		for (i = 0; i < nrc; ++i)
273*4328Scindi 			topo_node_unbind(rcs[rc]);
274*4328Scindi 	}
275*4328Scindi 
2762027Ssethg 	topo_mod_free(mod, rcs, nrc * sizeof (tnode_t *));
2772027Ssethg 	topo_mod_free(mod, hb, nhb * sizeof (tnode_t *));
278*4328Scindi 
279*4328Scindi 	return (err);
2801414Scindi }
2811414Scindi 
2821414Scindi /*
2831414Scindi  * declare_buses() assumes the elements in the provided busorrc list
2841414Scindi  * are sorted thusly:
2851414Scindi  *
2861414Scindi  *	(Hostbridge #0, Bus #0)
2871414Scindi  *	(Hostbridge #1, Bus #0)
2881414Scindi  *		...
2891414Scindi  *	(Hostbridge #nhb, Bus #0)
2901414Scindi  *	(Hostbridge #0, Bus #1)
2911414Scindi  *		...
2921414Scindi  *		...
2931414Scindi  *	(Hostbridge #nhb, Bus #(buses/hostbridge))
2941414Scindi  */
2951414Scindi int
declare_buses(topo_mod_t * mod,busorrc_t * list,tnode_t * ptn,int nhb)2963062Scindi declare_buses(topo_mod_t *mod, busorrc_t *list, tnode_t *ptn, int nhb)
2971414Scindi {
298*4328Scindi 	int err = 0;
2991414Scindi 	busorrc_t *p;
3001414Scindi 	tnode_t **hb;
3011414Scindi 	did_t *link;
3021414Scindi 	int br, bus;
3031414Scindi 
3041414Scindi 	/*
3051414Scindi 	 * Allocate an array to point at the hostbridge tnode_t pointers.
3061414Scindi 	 */
3072027Ssethg 	if ((hb = topo_mod_zalloc(mod, nhb * sizeof (tnode_t *))) == NULL)
3082027Ssethg 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
3091414Scindi 
3101414Scindi 	br = bus = 0;
3111414Scindi 	for (p = list; p != NULL; p = p->br_nextbus) {
3122027Ssethg 		topo_mod_dprintf(mod,
3131414Scindi 		    "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac);
3141414Scindi 
3153062Scindi 		if ((link =
316*4328Scindi 		    did_create(mod, p->br_din, 0, br, NO_RC, bus)) == NULL) {
317*4328Scindi 			err = -1;
318*4328Scindi 			break;
319*4328Scindi 		}
3201414Scindi 
3211414Scindi 		if (hb[br] == NULL) {
3223062Scindi 			hb[br] = hb_process(mod, ptn, br, bus, p->br_din, link);
323*4328Scindi 			if (hb[br] == NULL) {
324*4328Scindi 				err = -1;
325*4328Scindi 				break;
326*4328Scindi 			}
3271414Scindi 		} else {
3283062Scindi 			did_link_set(mod, hb[br], link);
3292027Ssethg 			if (topo_mod_enumerate(mod,
3303062Scindi 			    hb[br], PCI_BUS, PCI_BUS, bus, bus, link) < 0) {
331*4328Scindi 				err = -1;
332*4328Scindi 				break;
3331414Scindi 			}
3341414Scindi 		}
3351414Scindi 		br++;
3361414Scindi 		if (br == nhb) {
3371414Scindi 			br = 0;
3381414Scindi 			bus++;
3391414Scindi 		}
3401414Scindi 	}
341*4328Scindi 
342*4328Scindi 	if (err != 0) {
343*4328Scindi 		int i;
344*4328Scindi 
345*4328Scindi 		for (i = 0; i < nhb; ++i)
346*4328Scindi 			topo_node_unbind(hb[br]);
347*4328Scindi 	}
348*4328Scindi 
3492027Ssethg 	topo_mod_free(mod, hb, nhb * sizeof (tnode_t *));
350*4328Scindi 	return (err);
3511414Scindi }
352