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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <string.h> 28 #include <sys/fm/protocol.h> 29 #include <fm/topo_mod.h> 30 #include <fm/topo_hc.h> 31 #include <libdevinfo.h> 32 #include <limits.h> 33 #include <sys/param.h> 34 #include <sys/systeminfo.h> 35 36 #include <hostbridge.h> 37 #include <ioboard.h> 38 #include <did.h> 39 #include <did_props.h> 40 #include <util.h> 41 42 /* 43 * ioboard.c 44 * Generic code shared by all the ioboard enumerators 45 */ 46 47 static void iob_release(topo_mod_t *, tnode_t *); 48 static int iob_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 49 topo_instance_t, void *, void *); 50 static int iob_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 51 nvlist_t **); 52 53 extern int platform_iob_enum(topo_mod_t *, tnode_t *, topo_instance_t, 54 topo_instance_t); 55 extern int platform_iob_label(topo_mod_t *, tnode_t *, nvlist_t *, nvlist_t **); 56 57 extern txprop_t IOB_common_props[]; 58 extern int IOB_propcnt; 59 60 static const topo_modops_t Iob_ops = 61 { iob_enum, iob_release }; 62 static const topo_modinfo_t Iob_info = 63 { IOBOARD, FM_FMRI_SCHEME_HC, IOB_ENUMR_VERS, &Iob_ops }; 64 65 static const topo_method_t Iob_methods[] = { 66 { TOPO_METH_LABEL, TOPO_METH_LABEL_DESC, 67 TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, iob_label }, 68 { NULL } 69 }; 70 71 void 72 _topo_init(topo_mod_t *modhdl) 73 { 74 /* 75 * Turn on module debugging output 76 */ 77 if (getenv("TOPOIOBDBG") != NULL) 78 topo_mod_setdebug(modhdl); 79 topo_mod_dprintf(modhdl, "initializing ioboard enumerator\n"); 80 81 (void) topo_mod_register(modhdl, &Iob_info, TOPO_VERSION); 82 83 topo_mod_dprintf(modhdl, "Ioboard enumr initd\n"); 84 } 85 86 void 87 _topo_fini(topo_mod_t *modhdl) 88 { 89 topo_mod_unregister(modhdl); 90 } 91 92 static int 93 iob_label(topo_mod_t *mp, tnode_t *node, topo_version_t version, 94 nvlist_t *in, nvlist_t **out) 95 { 96 if (version > TOPO_METH_LABEL_VERSION) 97 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 98 return (platform_iob_label(mp, node, in, out)); 99 } 100 101 static topo_mod_t * 102 hb_enumr_load(topo_mod_t *mp) 103 { 104 topo_mod_t *rp = NULL; 105 106 if ((rp = topo_mod_load(mp, HOSTBRIDGE, HB_ENUMR_VERS)) == NULL) { 107 topo_mod_dprintf(mp, 108 "%s enumerator could not load %s.\n", IOBOARD, HOSTBRIDGE); 109 } 110 return (rp); 111 } 112 113 /*ARGSUSED*/ 114 static int 115 iob_enum(topo_mod_t *mp, tnode_t *pn, const char *name, topo_instance_t imin, 116 topo_instance_t imax, void *notused1, void *notused2) 117 { 118 topo_mod_t *hbmod; 119 int rv; 120 121 if (strcmp(name, IOBOARD) != 0) { 122 topo_mod_dprintf(mp, 123 "Currently only know how to enumerate %s components.\n", 124 IOBOARD); 125 return (0); 126 } 127 /* 128 * Load the hostbridge enumerator, we'll soon need it! 129 */ 130 if ((hbmod = hb_enumr_load(mp)) == NULL) { 131 return (-1); 132 } 133 134 if (did_hash_init(mp) != 0) 135 return (-1); 136 137 rv = platform_iob_enum(mp, pn, imin, imax); 138 139 did_hash_fini(mp); 140 topo_mod_unload(hbmod); 141 142 if (rv < 0) 143 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 144 else 145 return (0); 146 } 147 148 /*ARGSUSED*/ 149 static void 150 iob_release(topo_mod_t *mp, tnode_t *node) 151 { 152 153 /* 154 * node private data (did_t) for this node is destroyed in 155 * did_hash_destroy() 156 */ 157 158 topo_method_unregister_all(mp, node); 159 } 160 161 static tnode_t * 162 iob_tnode_create(topo_mod_t *mod, tnode_t *parent, 163 const char *name, topo_instance_t i, void *priv) 164 { 165 nvlist_t *fmri; 166 tnode_t *ntn; 167 nvlist_t *auth = topo_mod_auth(mod, parent); 168 169 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, 170 NULL, auth, NULL, NULL, NULL); 171 nvlist_free(auth); 172 if (fmri == NULL) { 173 topo_mod_dprintf(mod, 174 "Unable to make nvlist for %s bind.\n", name); 175 return (NULL); 176 } 177 ntn = topo_node_bind(mod, parent, name, i, fmri); 178 if (ntn == NULL) { 179 topo_mod_dprintf(mod, 180 "topo_node_bind (%s%d/%s%d) failed: %s\n", 181 topo_node_name(parent), topo_node_instance(parent), 182 name, i, 183 topo_strerror(topo_mod_errno(mod))); 184 nvlist_free(fmri); 185 return (NULL); 186 } 187 nvlist_free(fmri); 188 topo_node_setspecific(ntn, priv); 189 190 if (topo_method_register(mod, ntn, Iob_methods) < 0) { 191 topo_mod_dprintf(mod, "topo_method_register failed: %s\n", 192 topo_strerror(topo_mod_errno(mod))); 193 topo_node_unbind(ntn); 194 return (NULL); 195 } 196 return (ntn); 197 } 198 199 tnode_t * 200 ioboard_declare(topo_mod_t *mod, tnode_t *parent, topo_instance_t i, void *priv) 201 { 202 tnode_t *ntn; 203 204 if ((ntn = iob_tnode_create(mod, parent, IOBOARD, i, priv)) == NULL) 205 return (NULL); 206 if (did_props_set(ntn, priv, IOB_common_props, IOB_propcnt) < 0) { 207 topo_node_unbind(ntn); 208 return (NULL); 209 } 210 /* 211 * We expect to find host bridges beneath the ioboard. 212 */ 213 if (child_range_add(mod, ntn, HOSTBRIDGE, 0, MAX_HBS) < 0) { 214 topo_node_unbind(ntn); 215 return (NULL); 216 } 217 return (ntn); 218 } 219 220 did_t * 221 split_bus_address(topo_mod_t *mod, di_node_t dp, uint_t baseaddr, 222 uint_t bussep, int minbrd, int maxbrd, int *brd, int *br, int *bus) 223 { 224 uint_t bc, ac; 225 char *comma; 226 char *bac; 227 char *ba; 228 int e; 229 230 if ((ba = di_bus_addr(dp)) == NULL || 231 (bac = topo_mod_strdup(mod, ba)) == NULL) 232 return (NULL); 233 234 topo_mod_dprintf(mod, 235 "Transcribing %s into board, bus, etc.\n", bac); 236 237 if ((comma = strchr(bac, ',')) == NULL) { 238 topo_mod_strfree(mod, bac); 239 return (NULL); 240 } 241 *comma = '\0'; 242 bc = strtonum(mod, bac, &e); 243 *comma = ','; 244 if (e < 0) { 245 topo_mod_dprintf(mod, 246 "Trouble interpreting %s before comma.\n", bac); 247 topo_mod_strfree(mod, bac); 248 return (NULL); 249 } 250 ac = strtonum(mod, comma + 1, &e); 251 if (e < 0) { 252 topo_mod_dprintf(mod, 253 "Trouble interpreting %s after comma.\n", bac); 254 topo_mod_strfree(mod, bac); 255 return (NULL); 256 } 257 topo_mod_strfree(mod, bac); 258 259 *brd = ((bc - baseaddr) / bussep) + minbrd; 260 *br = (bc - baseaddr) % bussep; 261 *bus = ((ac == IOB_BUSADDR1) ? 0 : 1); 262 if (*brd < minbrd || *brd > maxbrd || (*br != 0 && *br != 1) || 263 (ac != IOB_BUSADDR1 && ac != IOB_BUSADDR2)) { 264 topo_mod_dprintf(mod, "Trouble with transcription\n"); 265 topo_mod_dprintf(mod, "brd=%d br=%d bus=%d bc=%x ac=%x\n", 266 *brd, *br, *bus, bc, ac); 267 return (NULL); 268 } 269 return (did_create(mod, dp, *brd, *br, NO_RC, *bus)); 270 } 271