xref: /onnv-gate/usr/src/lib/fm/topo/modules/sun4u/hostbridge/hb_sun4u.c (revision 3062:46d280f5351d)
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 /*
231414Scindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241414Scindi  * Use is subject to license terms.
251414Scindi  */
261414Scindi 
271414Scindi #pragma ident	"%Z%%M%	%I%	%E% SMI"
281414Scindi 
29*3062Scindi #include <fm/topo_hc.h>
30*3062Scindi 
31*3062Scindi #include <hb_sun4.h>
32*3062Scindi #include <hostbridge.h>
33*3062Scindi #include <pcibus.h>
34*3062Scindi #include <util.h>
351414Scindi 
361414Scindi int
count_busorrc(topo_mod_t * mod,busorrc_t * list,int * hbc,int * bph)37*3062Scindi count_busorrc(topo_mod_t *mod, busorrc_t *list, int *hbc, int *bph)
381414Scindi {
391414Scindi 	ulong_t start;
401414Scindi 	busorrc_t *p;
411414Scindi 	int bt;
421414Scindi 
431414Scindi 	start = list->br_ba_ac;
441414Scindi 	p = list->br_nextbus;
451414Scindi 	bt = *hbc = 1;
461414Scindi 	while (p != NULL) {
471414Scindi 		if (p->br_ba_ac == start)
481414Scindi 			(*hbc)++;
491414Scindi 		bt++;
501414Scindi 		p = p->br_nextbus;
511414Scindi 	}
521414Scindi 
531414Scindi 	/*
541414Scindi 	 * sanity check that we have the correct number of buses/root
551414Scindi 	 * complexes in the list to have the same number of buses on
561414Scindi 	 * each hostbridge
571414Scindi 	 */
581414Scindi 	if (bt % *hbc != 0) {
592027Ssethg 		topo_mod_dprintf(mod,
601414Scindi 		    "Imbalance between bus/root complex count and "
611414Scindi 		    "the number of hostbridges.\n");
622027Ssethg 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
631414Scindi 	}
641414Scindi 	*bph = bt / *hbc;
652027Ssethg 	topo_mod_dprintf(mod,
661414Scindi 	    "%d hostbridge%s\n", *hbc, (*hbc > 1) ? "s." : ".");
672027Ssethg 	topo_mod_dprintf(mod, "%d buses total.\n", bt);
681414Scindi 	return (0);
691414Scindi }
701414Scindi 
711414Scindi static int
busorrc_process(topo_mod_t * mod,busorrc_t * list,int isrc,tnode_t * ptn)72*3062Scindi busorrc_process(topo_mod_t *mod, busorrc_t *list, int isrc, tnode_t *ptn)
731414Scindi {
741414Scindi 	int hbc, busper;
751414Scindi 
761414Scindi 	if (list == NULL) {
771414Scindi 		if (isrc == 1)
782027Ssethg 			topo_mod_dprintf(mod, "No root complexes found.\n");
791414Scindi 		else
802027Ssethg 			topo_mod_dprintf(mod, "No pci buses found.\n");
811414Scindi 		return (0);
821414Scindi 	}
831414Scindi 
841414Scindi 	/*
851414Scindi 	 * At this point we've looked through all the top-level device
861414Scindi 	 * tree nodes for instances of drivers that represent logical
871414Scindi 	 * PCI buses or root complexes.  We've sorted them into a
881414Scindi 	 * list, ordered by "bus address".  We retrieved "bus address"
891414Scindi 	 * using di_bus_addr().  That gave us a string that contains
901414Scindi 	 * either a single hex number or a pair of them separated by a
911414Scindi 	 * comma.  If there was a single number, we've assumed the
921414Scindi 	 * second number to be zero.
931414Scindi 	 *
941414Scindi 	 * So, we always have a pair of numbers describing a bus/root
951414Scindi 	 * complex, X1 and X2, with X1 being the number before the
961414Scindi 	 * comma, and X2 being the number after (or the assumed zero).
971414Scindi 	 * As each node was examined, we then sorted these buses/root
981414Scindi 	 * complexes, first by the value of X2, and using X1 to order
991414Scindi 	 * amongst buses/root complexes with the same value for X2.
1001414Scindi 	 *
1011414Scindi 	 * We infer the existence of hostbridges by observing a
1021414Scindi 	 * pattern that X2 is recycled for different hostbridges, and
1031414Scindi 	 * that sorting by X1 within buses/root complexes with equal
1041414Scindi 	 * values of X2 maintains the correct associations of
1051414Scindi 	 * buses/root complexes and bridges.
1061414Scindi 	 */
107*3062Scindi 	if (count_busorrc(mod, list, &hbc, &busper) < 0)
1081414Scindi 		return (-1);
1091414Scindi 	if (isrc == 1)
110*3062Scindi 		return (declare_exbuses(mod, list, ptn, hbc, busper));
1111414Scindi 	else
112*3062Scindi 		return (declare_buses(mod, list, ptn, hbc));
1131414Scindi }
1141414Scindi 
1151414Scindi static int
pci_hostbridges_find(topo_mod_t * mod,tnode_t * ptn)116*3062Scindi pci_hostbridges_find(topo_mod_t *mod, tnode_t *ptn)
1171414Scindi {
1181414Scindi 	busorrc_t *buses = NULL;
1191414Scindi 	busorrc_t *rcs = NULL;
1201414Scindi 	di_node_t devtree;
1211414Scindi 	di_node_t pnode;
1221414Scindi 
1231414Scindi 	/* Scan for buses, top-level devinfo nodes with the right driver */
124*3062Scindi 	devtree = topo_mod_devinfo(mod);
1251414Scindi 	if (devtree == DI_NODE_NIL) {
1262027Ssethg 		topo_mod_dprintf(mod, "devinfo init failed.");
1271414Scindi 		topo_node_range_destroy(ptn, HOSTBRIDGE);
1282027Ssethg 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1291414Scindi 	}
1301414Scindi 
1311414Scindi 	pnode = di_drv_first_node(PCI, devtree);
1321414Scindi 	while (pnode != DI_NODE_NIL) {
133*3062Scindi 		if (busorrc_add(mod, &buses, pnode) < 0) {
1342027Ssethg 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1351414Scindi 		}
1361414Scindi 		pnode = di_drv_next_node(pnode);
1371414Scindi 	}
1381414Scindi 	pnode = di_drv_first_node(PSYCHO, devtree);
1391414Scindi 	while (pnode != DI_NODE_NIL) {
140*3062Scindi 		if (busorrc_add(mod, &buses, pnode) < 0) {
1412027Ssethg 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1421414Scindi 		}
1431414Scindi 		pnode = di_drv_next_node(pnode);
1441414Scindi 	}
1451414Scindi 	pnode = di_drv_first_node(SCHIZO, devtree);
1461414Scindi 	while (pnode != DI_NODE_NIL) {
147*3062Scindi 		if (busorrc_add(mod, &buses, pnode) < 0) {
1482027Ssethg 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1491414Scindi 		}
1501414Scindi 		pnode = di_drv_next_node(pnode);
1511414Scindi 	}
1521414Scindi 	pnode = di_drv_first_node(PX, devtree);
1531414Scindi 	while (pnode != DI_NODE_NIL) {
154*3062Scindi 		if (busorrc_add(mod, &rcs, pnode) < 0) {
1552027Ssethg 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1561414Scindi 		}
1571414Scindi 		pnode = di_drv_next_node(pnode);
1581414Scindi 	}
159*3062Scindi 	if (busorrc_process(mod, buses, 0, ptn) < 0)
1602027Ssethg 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1611414Scindi 
162*3062Scindi 	if (busorrc_process(mod, rcs, 1, ptn) < 0)
1632027Ssethg 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1641414Scindi 
165*3062Scindi 	busorrc_free(mod, buses);
166*3062Scindi 	busorrc_free(mod, rcs);
1671414Scindi 	return (0);
1681414Scindi }
1691414Scindi 
1701414Scindi /*ARGSUSED*/
1711414Scindi int
platform_hb_enum(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t imin,topo_instance_t imax)172*3062Scindi platform_hb_enum(topo_mod_t *mod, tnode_t *parent, const char *name,
173*3062Scindi     topo_instance_t imin, topo_instance_t imax)
1741414Scindi {
175*3062Scindi 	return (pci_hostbridges_find(mod, parent));
1761414Scindi }
1771414Scindi 
1781414Scindi /*ARGSUSED*/
1791414Scindi int
platform_hb_label(topo_mod_t * mod,tnode_t * node,nvlist_t * in,nvlist_t ** out)180*3062Scindi platform_hb_label(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out)
1811414Scindi {
1822027Ssethg 	return (labelmethod_inherit(mod, node, in, out));
1831414Scindi }
184