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 <strings.h> 29 #include <libdevinfo.h> 30 #include <fm/topo_mod.h> 31 #include <fm/topo_hc.h> 32 #include <sys/fm/protocol.h> 33 #include "opl_topo.h" 34 35 static const topo_pgroup_info_t io_pgroup = 36 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 37 static const topo_pgroup_info_t pci_pgroup = 38 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 39 40 /* 41 * Check the root complex device node for a slot-names property. 42 */ 43 const char * 44 opl_get_slot_name(topo_mod_t *mod, di_node_t n) 45 { 46 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 47 di_prom_prop_t pp = DI_PROM_PROP_NIL; 48 uchar_t *buf; 49 50 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_PROP_NIL) 51 return (NULL); 52 53 for (pp = di_prom_prop_next(ptp, n, pp); 54 pp != DI_PROM_PROP_NIL; 55 pp = di_prom_prop_next(ptp, n, pp)) { 56 if (strcmp(di_prom_prop_name(pp), OPL_SLOT_NAMES) == 0) { 57 if (di_prom_prop_data(pp, &buf) <= sizeof (uint32_t)) 58 continue; 59 return ((const char *)&buf[4]); 60 } 61 } 62 return (NULL); 63 } 64 65 static tnode_t * 66 opl_node_create(topo_mod_t *mp, tnode_t *parent, const char *name, int inst, 67 void *priv) 68 { 69 tnode_t *node; 70 nvlist_t *fmri; 71 nvlist_t *auth = topo_mod_auth(mp, parent); 72 73 if (parent == NULL || inst < 0) { 74 return (NULL); 75 } 76 77 /* Create FMRI */ 78 if ((fmri = topo_mod_hcfmri(mp, parent, FM_HC_SCHEME_VERSION, name, 79 inst, NULL, auth, NULL, NULL, NULL)) == NULL) { 80 topo_mod_dprintf(mp, "create of tnode for %s failed: %s", 81 name, topo_strerror(topo_mod_errno(mp))); 82 nvlist_free(auth); 83 return (NULL); 84 } 85 nvlist_free(auth); 86 87 /* Create and bind node */ 88 node = topo_node_bind(mp, parent, name, inst, fmri); 89 if (node == NULL) { 90 nvlist_free(fmri); 91 topo_mod_dprintf(mp, "unable to bind root complex: %s\n", 92 topo_strerror(topo_mod_errno(mp))); 93 return (NULL); /* mod_errno already set */ 94 } 95 96 nvlist_free(fmri); 97 topo_node_setspecific(node, priv); 98 99 return (node); 100 } 101 102 /* 103 * Create a root complex node. 104 */ 105 static tnode_t * 106 opl_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode, int inst) 107 { 108 int err; 109 tnode_t *rcn; 110 const char *slot_name; 111 char *dnpath; 112 nvlist_t *mod; 113 114 rcn = opl_node_create(mp, parent, PCIEX_ROOT, inst, (void *)dnode); 115 if (rcn == NULL) { 116 return (NULL); 117 } 118 119 /* 120 * If this root complex connects to a slot, it will have a 121 * slot-names property. 122 */ 123 slot_name = opl_get_slot_name(mp, dnode); 124 if (slot_name) { 125 char fru_str[64]; 126 nvlist_t *fru_fmri; 127 /* Add FRU fmri */ 128 (void) snprintf(fru_str, sizeof (fru_str), "hc:///component=%s", 129 slot_name); 130 if (topo_mod_str2nvl(mp, fru_str, &fru_fmri) == 0) { 131 (void) topo_node_fru_set(rcn, fru_fmri, 0, &err); 132 nvlist_free(fru_fmri); 133 } 134 /* Add label */ 135 (void) topo_node_label_set(rcn, (char *)slot_name, &err); 136 } else { 137 /* Inherit parent FRU's label */ 138 (void) topo_node_fru_set(rcn, NULL, 0, &err); 139 (void) topo_node_label_set(rcn, NULL, &err); 140 } 141 142 /* 143 * Set ASRU to be the dev-scheme ASRU 144 */ 145 if ((dnpath = di_devfs_path(dnode)) != NULL) { 146 nvlist_t *fmri; 147 148 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION, 149 dnpath, NULL); 150 if (fmri == NULL) { 151 topo_mod_dprintf(mp, 152 "dev:///%s fmri creation failed.\n", 153 dnpath); 154 (void) topo_mod_seterrno(mp, err); 155 di_devfs_path_free(dnpath); 156 return (NULL); 157 } 158 if (topo_node_asru_set(rcn, fmri, 0, &err) < 0) { 159 topo_mod_dprintf(mp, "topo_node_asru_set failed\n"); 160 (void) topo_mod_seterrno(mp, err); 161 nvlist_free(fmri); 162 di_devfs_path_free(dnpath); 163 return (NULL); 164 } 165 nvlist_free(fmri); 166 } else { 167 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 168 } 169 170 /* 171 * Set pciexrc properties for root complex nodes 172 */ 173 174 /* Add the io and pci property groups */ 175 if (topo_pgroup_create(rcn, &io_pgroup, &err) < 0) { 176 topo_mod_dprintf(mp, "topo_pgroup_create failed\n"); 177 di_devfs_path_free(dnpath); 178 (void) topo_mod_seterrno(mp, err); 179 return (NULL); 180 } 181 if (topo_pgroup_create(rcn, &pci_pgroup, &err) < 0) { 182 topo_mod_dprintf(mp, "topo_pgroup_create failed\n"); 183 di_devfs_path_free(dnpath); 184 (void) topo_mod_seterrno(mp, err); 185 return (NULL); 186 } 187 /* Add the devfs path property */ 188 if (dnpath) { 189 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEV, 190 TOPO_PROP_IMMUTABLE, dnpath, &err) != 0) { 191 topo_mod_dprintf(mp, "Failed to set DEV property\n"); 192 di_devfs_path_free(dnpath); 193 (void) topo_mod_seterrno(mp, err); 194 } 195 di_devfs_path_free(dnpath); 196 } 197 /* Oberon device type is always "pciex" */ 198 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE, 199 TOPO_PROP_IMMUTABLE, OPL_PX_DEVTYPE, &err) != 0) { 200 topo_mod_dprintf(mp, "Failed to set DEVTYPE property\n"); 201 } 202 /* Oberon driver is always "px" */ 203 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DRIVER, 204 TOPO_PROP_IMMUTABLE, OPL_PX_DRV, &err) != 0) { 205 topo_mod_dprintf(mp, "Failed to set DRIVER property\n"); 206 } 207 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, OPL_PX_DRV)) 208 == NULL || topo_prop_set_fmri(rcn, TOPO_PGROUP_IO, 209 TOPO_IO_MODULE, TOPO_PROP_IMMUTABLE, mod, &err) != 0) { 210 topo_mod_dprintf(mp, "Failed to set MODULE property\n"); 211 } 212 if (mod != NULL) 213 nvlist_free(mod); 214 215 /* This is a PCIEX Root Complex */ 216 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP, 217 TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) { 218 topo_mod_dprintf(mp, "Failed to set EXCAP property\n"); 219 } 220 /* BDF of Oberon root complex is constant */ 221 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, 222 TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, OPL_PX_BDF, &err) != 0) { 223 topo_mod_dprintf(mp, "Failed to set EXCAP property\n"); 224 } 225 226 /* Make room for children */ 227 (void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, OPL_BUS_MAX); 228 return (rcn); 229 } 230 231 /* 232 * Create a hostbridge node. 233 */ 234 static tnode_t * 235 opl_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst) 236 { 237 int err; 238 tnode_t *hbn; 239 240 hbn = opl_node_create(mp, parent, HOSTBRIDGE, inst, NULL); 241 if (hbn == NULL) { 242 return (NULL); 243 } 244 245 /* Inherit parent FRU's label */ 246 (void) topo_node_fru_set(hbn, NULL, 0, &err); 247 (void) topo_node_label_set(hbn, NULL, &err); 248 249 /* Make room for children */ 250 (void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, OPL_RC_MAX); 251 252 return (hbn); 253 } 254 255 /* 256 * opl_hb_enum gets the ioboard instance passed in, and determines the 257 * hostbridge and root complex instances numbers based on the bus addresses. 258 */ 259 int 260 opl_hb_enum(topo_mod_t *mp, const ioboard_contents_t *iob, tnode_t *ion, 261 int brd) 262 { 263 int hb; 264 int rc; 265 di_node_t p; 266 tnode_t *hbnode; 267 tnode_t *rcnode; 268 topo_mod_t *pcimod; 269 270 /* Load the pcibus module. We'll need it later. */ 271 pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS); 272 if (pcimod == NULL) { 273 topo_mod_dprintf(mp, "can't load pcibus module: %s\n", 274 topo_strerror(topo_mod_errno(mp))); 275 return (-1); 276 } 277 278 /* For each hostbridge on an ioboard... */ 279 for (hb = 0; hb < OPL_HB_MAX; hb++) { 280 hbnode = NULL; 281 /* For each root complex in a hostbridge... */ 282 for (rc = 0; rc < OPL_RC_MAX; rc++) { 283 p = iob->rcs[hb][rc]; 284 /* If no root complex, continue */ 285 if (p == DI_NODE_NIL) { 286 continue; 287 } 288 289 /* The root complex exists! */ 290 topo_mod_dprintf(mp, "declaring " 291 "/chassis=0/ioboard=%d/hostbridge=%d/pciexrc=%d\n", 292 brd, hb, rc); 293 294 /* 295 * If we haven't created a hostbridge node yet, do it 296 * now. 297 */ 298 if (hbnode == NULL) { 299 hbnode = opl_hb_node_create(mp, ion, hb); 300 if (hbnode == NULL) { 301 topo_mod_dprintf(mp, 302 "unable to create hbnode: %s\n", 303 topo_strerror(topo_mod_errno(mp))); 304 topo_mod_unload(pcimod); 305 return (-1); 306 } 307 308 } 309 310 /* Create the root complex node */ 311 rcnode = opl_rc_node_create(mp, hbnode, p, rc); 312 if (rcnode == NULL) { 313 topo_mod_dprintf(mp, 314 "unable to create rcnode: %s\n", 315 topo_strerror(topo_mod_errno(mp))); 316 topo_mod_unload(pcimod); 317 return (-1); 318 } 319 320 /* Enumerate pcibus nodes under the root complex */ 321 if (topo_mod_enumerate(pcimod, rcnode, 322 PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) { 323 topo_mod_dprintf(mp, 324 "error enumerating pcibus: %s\n", 325 topo_strerror(topo_mod_errno(mp))); 326 topo_mod_unload(pcimod); 327 return (-1); 328 } 329 } 330 } 331 topo_mod_unload(pcimod); 332 return (0); 333 }