xref: /titanic_50/usr/src/lib/fm/topo/modules/sun4u/hostbridge/hb_sun4u.c (revision 0eb822a1c0c2bea495647510b75f77f0e57633eb)
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 2006 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 <fm/topo_hc.h>
30 
31 #include <hb_sun4.h>
32 #include <hostbridge.h>
33 #include <pcibus.h>
34 #include <util.h>
35 
36 int
count_busorrc(topo_mod_t * mod,busorrc_t * list,int * hbc,int * bph)37 count_busorrc(topo_mod_t *mod, busorrc_t *list, int *hbc, int *bph)
38 {
39 	ulong_t start;
40 	busorrc_t *p;
41 	int bt;
42 
43 	start = list->br_ba_ac;
44 	p = list->br_nextbus;
45 	bt = *hbc = 1;
46 	while (p != NULL) {
47 		if (p->br_ba_ac == start)
48 			(*hbc)++;
49 		bt++;
50 		p = p->br_nextbus;
51 	}
52 
53 	/*
54 	 * sanity check that we have the correct number of buses/root
55 	 * complexes in the list to have the same number of buses on
56 	 * each hostbridge
57 	 */
58 	if (bt % *hbc != 0) {
59 		topo_mod_dprintf(mod,
60 		    "Imbalance between bus/root complex count and "
61 		    "the number of hostbridges.\n");
62 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
63 	}
64 	*bph = bt / *hbc;
65 	topo_mod_dprintf(mod,
66 	    "%d hostbridge%s\n", *hbc, (*hbc > 1) ? "s." : ".");
67 	topo_mod_dprintf(mod, "%d buses total.\n", bt);
68 	return (0);
69 }
70 
71 static int
busorrc_process(topo_mod_t * mod,busorrc_t * list,int isrc,tnode_t * ptn)72 busorrc_process(topo_mod_t *mod, busorrc_t *list, int isrc, tnode_t *ptn)
73 {
74 	int hbc, busper;
75 
76 	if (list == NULL) {
77 		if (isrc == 1)
78 			topo_mod_dprintf(mod, "No root complexes found.\n");
79 		else
80 			topo_mod_dprintf(mod, "No pci buses found.\n");
81 		return (0);
82 	}
83 
84 	/*
85 	 * At this point we've looked through all the top-level device
86 	 * tree nodes for instances of drivers that represent logical
87 	 * PCI buses or root complexes.  We've sorted them into a
88 	 * list, ordered by "bus address".  We retrieved "bus address"
89 	 * using di_bus_addr().  That gave us a string that contains
90 	 * either a single hex number or a pair of them separated by a
91 	 * comma.  If there was a single number, we've assumed the
92 	 * second number to be zero.
93 	 *
94 	 * So, we always have a pair of numbers describing a bus/root
95 	 * complex, X1 and X2, with X1 being the number before the
96 	 * comma, and X2 being the number after (or the assumed zero).
97 	 * As each node was examined, we then sorted these buses/root
98 	 * complexes, first by the value of X2, and using X1 to order
99 	 * amongst buses/root complexes with the same value for X2.
100 	 *
101 	 * We infer the existence of hostbridges by observing a
102 	 * pattern that X2 is recycled for different hostbridges, and
103 	 * that sorting by X1 within buses/root complexes with equal
104 	 * values of X2 maintains the correct associations of
105 	 * buses/root complexes and bridges.
106 	 */
107 	if (count_busorrc(mod, list, &hbc, &busper) < 0)
108 		return (-1);
109 	if (isrc == 1)
110 		return (declare_exbuses(mod, list, ptn, hbc, busper));
111 	else
112 		return (declare_buses(mod, list, ptn, hbc));
113 }
114 
115 static int
pci_hostbridges_find(topo_mod_t * mod,tnode_t * ptn)116 pci_hostbridges_find(topo_mod_t *mod, tnode_t *ptn)
117 {
118 	busorrc_t *buses = NULL;
119 	busorrc_t *rcs = NULL;
120 	di_node_t devtree;
121 	di_node_t pnode;
122 
123 	/* Scan for buses, top-level devinfo nodes with the right driver */
124 	devtree = topo_mod_devinfo(mod);
125 	if (devtree == DI_NODE_NIL) {
126 		topo_mod_dprintf(mod, "devinfo init failed.");
127 		topo_node_range_destroy(ptn, HOSTBRIDGE);
128 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
129 	}
130 
131 	pnode = di_drv_first_node(PCI, devtree);
132 	while (pnode != DI_NODE_NIL) {
133 		if (busorrc_add(mod, &buses, pnode) < 0) {
134 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
135 		}
136 		pnode = di_drv_next_node(pnode);
137 	}
138 	pnode = di_drv_first_node(PSYCHO, devtree);
139 	while (pnode != DI_NODE_NIL) {
140 		if (busorrc_add(mod, &buses, pnode) < 0) {
141 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
142 		}
143 		pnode = di_drv_next_node(pnode);
144 	}
145 	pnode = di_drv_first_node(SCHIZO, devtree);
146 	while (pnode != DI_NODE_NIL) {
147 		if (busorrc_add(mod, &buses, pnode) < 0) {
148 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
149 		}
150 		pnode = di_drv_next_node(pnode);
151 	}
152 	pnode = di_drv_first_node(PX, devtree);
153 	while (pnode != DI_NODE_NIL) {
154 		if (busorrc_add(mod, &rcs, pnode) < 0) {
155 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
156 		}
157 		pnode = di_drv_next_node(pnode);
158 	}
159 	if (busorrc_process(mod, buses, 0, ptn) < 0)
160 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
161 
162 	if (busorrc_process(mod, rcs, 1, ptn) < 0)
163 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
164 
165 	busorrc_free(mod, buses);
166 	busorrc_free(mod, rcs);
167 	return (0);
168 }
169 
170 /*ARGSUSED*/
171 int
platform_hb_enum(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t imin,topo_instance_t imax)172 platform_hb_enum(topo_mod_t *mod, tnode_t *parent, const char *name,
173     topo_instance_t imin, topo_instance_t imax)
174 {
175 	return (pci_hostbridges_find(mod, parent));
176 }
177 
178 /*ARGSUSED*/
179 int
platform_hb_label(topo_mod_t * mod,tnode_t * node,nvlist_t * in,nvlist_t ** out)180 platform_hb_label(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out)
181 {
182 	return (labelmethod_inherit(mod, node, in, out));
183 }
184