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 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 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 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 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 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