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