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 nvlist_free(mod); 213 214 /* This is a PCIEX Root Complex */ 215 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP, 216 TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) { 217 topo_mod_dprintf(mp, "Failed to set EXCAP property\n"); 218 } 219 /* BDF of Oberon root complex is constant */ 220 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, 221 TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, OPL_PX_BDF, &err) != 0) { 222 topo_mod_dprintf(mp, "Failed to set EXCAP property\n"); 223 } 224 225 /* Make room for children */ 226 (void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, OPL_BUS_MAX); 227 return (rcn); 228 } 229 230 /* 231 * Create a hostbridge node. 232 */ 233 static tnode_t * 234 opl_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst) 235 { 236 int err; 237 tnode_t *hbn; 238 239 hbn = opl_node_create(mp, parent, HOSTBRIDGE, inst, NULL); 240 if (hbn == NULL) { 241 return (NULL); 242 } 243 244 /* Inherit parent FRU's label */ 245 (void) topo_node_fru_set(hbn, NULL, 0, &err); 246 (void) topo_node_label_set(hbn, NULL, &err); 247 248 /* Make room for children */ 249 (void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, OPL_RC_MAX); 250 251 return (hbn); 252 } 253 254 /* 255 * opl_hb_enum gets the ioboard instance passed in, and determines the 256 * hostbridge and root complex instances numbers based on the bus addresses. 257 */ 258 int 259 opl_hb_enum(topo_mod_t *mp, const ioboard_contents_t *iob, tnode_t *ion, 260 int brd) 261 { 262 int hb; 263 int rc; 264 di_node_t p; 265 tnode_t *hbnode; 266 tnode_t *rcnode; 267 topo_mod_t *pcimod; 268 269 /* Load the pcibus module. We'll need it later. */ 270 pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS); 271 if (pcimod == NULL) { 272 topo_mod_dprintf(mp, "can't load pcibus module: %s\n", 273 topo_strerror(topo_mod_errno(mp))); 274 return (-1); 275 } 276 277 /* For each hostbridge on an ioboard... */ 278 for (hb = 0; hb < OPL_HB_MAX; hb++) { 279 hbnode = NULL; 280 /* For each root complex in a hostbridge... */ 281 for (rc = 0; rc < OPL_RC_MAX; rc++) { 282 p = iob->rcs[hb][rc]; 283 /* If no root complex, continue */ 284 if (p == DI_NODE_NIL) { 285 continue; 286 } 287 288 /* The root complex exists! */ 289 topo_mod_dprintf(mp, "declaring " 290 "/chassis=0/ioboard=%d/hostbridge=%d/pciexrc=%d\n", 291 brd, hb, rc); 292 293 /* 294 * If we haven't created a hostbridge node yet, do it 295 * now. 296 */ 297 if (hbnode == NULL) { 298 hbnode = opl_hb_node_create(mp, ion, hb); 299 if (hbnode == NULL) { 300 topo_mod_dprintf(mp, 301 "unable to create hbnode: %s\n", 302 topo_strerror(topo_mod_errno(mp))); 303 topo_mod_unload(pcimod); 304 return (-1); 305 } 306 307 } 308 309 /* Create the root complex node */ 310 rcnode = opl_rc_node_create(mp, hbnode, p, rc); 311 if (rcnode == NULL) { 312 topo_mod_dprintf(mp, 313 "unable to create rcnode: %s\n", 314 topo_strerror(topo_mod_errno(mp))); 315 topo_mod_unload(pcimod); 316 return (-1); 317 } 318 319 /* Enumerate pcibus nodes under the root complex */ 320 if (topo_mod_enumerate(pcimod, rcnode, 321 PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) { 322 topo_mod_dprintf(mp, 323 "error enumerating pcibus: %s\n", 324 topo_strerror(topo_mod_errno(mp))); 325 topo_mod_unload(pcimod); 326 return (-1); 327 } 328 } 329 } 330 topo_mod_unload(pcimod); 331 return (0); 332 } 333