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 "cpuboard_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 static tnode_t * 41 cpuboard_node_create(topo_mod_t *mp, tnode_t *parent, const char *name, 42 int inst, void *priv) 43 { 44 tnode_t *node; 45 nvlist_t *fmri; 46 nvlist_t *auth = topo_mod_auth(mp, parent); 47 48 topo_mod_dprintf(mp, "cpuboard_node_create:\n"); 49 50 if (parent == NULL || inst < 0) { 51 return (NULL); 52 } 53 54 /* Create FMRI */ 55 if ((fmri = topo_mod_hcfmri(mp, parent, FM_HC_SCHEME_VERSION, name, 56 inst, NULL, auth, NULL, NULL, NULL)) == NULL) { 57 topo_mod_dprintf(mp, "create of tnode for %s failed: %s", 58 name, topo_strerror(topo_mod_errno(mp))); 59 nvlist_free(auth); 60 return (NULL); 61 } 62 nvlist_free(auth); 63 64 /* Create and bind node */ 65 node = topo_node_bind(mp, parent, name, inst, fmri); 66 if (node == NULL) { 67 nvlist_free(fmri); 68 topo_mod_dprintf(mp, "unable to bind root complex: %s\n", 69 topo_strerror(topo_mod_errno(mp))); 70 return (NULL); /* mod_errno already set */ 71 } 72 73 nvlist_free(fmri); 74 topo_node_setspecific(node, priv); 75 76 return (node); 77 } 78 79 /* 80 * cpuboard_rc_node_create() 81 * Description: 82 * Create a root complex node pciexrc 83 * Parameters: 84 * mp: topo module pointer 85 * parent: topo parent node of the newly created pciexrc node 86 * dnode: Solaris device node of the root complex 87 * rcpath: Used to populated the dev property of the topo pciexrc node if 88 * the local host does not own the root complex. 89 */ 90 static tnode_t * 91 cpuboard_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode, 92 char *rcpath, int inst) 93 { 94 int err; 95 tnode_t *rcn; 96 char *dnpath; 97 nvlist_t *mod; 98 99 topo_mod_dprintf(mp, "cpuboard_rc_node_create:\n"); 100 101 rcn = cpuboard_node_create(mp, parent, PCIEX_ROOT, inst, (void *)dnode); 102 if (rcn == NULL) { 103 return (NULL); 104 } 105 106 /* Inherit parent FRU's label */ 107 (void) topo_node_fru_set(rcn, NULL, 0, &err); 108 (void) topo_node_label_set(rcn, NULL, &err); 109 110 /* 111 * Set ASRU to be the dev-scheme ASRU 112 */ 113 if ((dnpath = di_devfs_path(dnode)) != NULL) { 114 nvlist_t *fmri; 115 116 /* 117 * The local host owns the root complex, so use the dev path 118 * from the di_devfs_path(), instead of the passed in rcpath, 119 * to populate the dev property. 120 */ 121 rcpath = dnpath; 122 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION, 123 dnpath, NULL); 124 if (fmri == NULL) { 125 topo_mod_dprintf(mp, 126 "dev:///%s fmri creation failed.\n", 127 dnpath); 128 (void) topo_mod_seterrno(mp, err); 129 di_devfs_path_free(dnpath); 130 return (NULL); 131 } 132 if (topo_node_asru_set(rcn, fmri, 0, &err) < 0) { 133 topo_mod_dprintf(mp, "topo_node_asru_set failed\n"); 134 (void) topo_mod_seterrno(mp, err); 135 nvlist_free(fmri); 136 di_devfs_path_free(dnpath); 137 return (NULL); 138 } 139 nvlist_free(fmri); 140 } else { 141 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 142 } 143 144 /* 145 * Set pciexrc properties for root complex nodes 146 */ 147 148 /* Add the io and pci property groups */ 149 if (topo_pgroup_create(rcn, &io_pgroup, &err) < 0) { 150 topo_mod_dprintf(mp, "topo_pgroup_create failed\n"); 151 di_devfs_path_free(dnpath); 152 (void) topo_mod_seterrno(mp, err); 153 return (NULL); 154 } 155 if (topo_pgroup_create(rcn, &pci_pgroup, &err) < 0) { 156 topo_mod_dprintf(mp, "topo_pgroup_create failed\n"); 157 di_devfs_path_free(dnpath); 158 (void) topo_mod_seterrno(mp, err); 159 return (NULL); 160 } 161 /* Add the devfs path property */ 162 if (rcpath) { 163 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEV, 164 TOPO_PROP_IMMUTABLE, rcpath, &err) != 0) { 165 topo_mod_dprintf(mp, "Failed to set DEV property\n"); 166 (void) topo_mod_seterrno(mp, err); 167 } 168 } 169 if (dnpath) { 170 di_devfs_path_free(dnpath); 171 } 172 /* T5440 device type is always "pciex" */ 173 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE, 174 TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DEVTYPE, &err) != 0) { 175 topo_mod_dprintf(mp, "Failed to set DEVTYPE property\n"); 176 } 177 /* T5440 driver is always "px" */ 178 if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DRIVER, 179 TOPO_PROP_IMMUTABLE, CPUBOARD_PX_DRV, &err) != 0) { 180 topo_mod_dprintf(mp, "Failed to set DRIVER property\n"); 181 } 182 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, CPUBOARD_PX_DRV)) 183 == NULL || topo_prop_set_fmri(rcn, TOPO_PGROUP_IO, 184 TOPO_IO_MODULE, TOPO_PROP_IMMUTABLE, mod, &err) != 0) { 185 topo_mod_dprintf(mp, "Failed to set MODULE property\n"); 186 } 187 nvlist_free(mod); 188 189 /* This is a PCIEX Root Complex */ 190 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP, 191 TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) { 192 topo_mod_dprintf(mp, "Failed to set EXCAP property\n"); 193 } 194 /* BDF of T5440 root complex is constant */ 195 if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, 196 TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, CPUBOARD_PX_BDF, &err) != 0) { 197 topo_mod_dprintf(mp, "Failed to set EXCAP property\n"); 198 } 199 200 /* Make room for children */ 201 (void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, CPUBOARD_MAX); 202 return (rcn); 203 } 204 205 /* 206 * Create a hostbridge node. 207 */ 208 static tnode_t * 209 cpuboard_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst) 210 { 211 int err; 212 tnode_t *hbn; 213 214 topo_mod_dprintf(mp, "cpuboard_hb_node_create: parent=%p, inst=%d\n", 215 parent, inst); 216 217 hbn = cpuboard_node_create(mp, parent, HOSTBRIDGE, inst, NULL); 218 if (hbn == NULL) { 219 topo_mod_dprintf(mp, "cpuboard_hb_node_create: " 220 "cpuboard_node_create() failed.\n"); 221 return (NULL); 222 } 223 224 /* Inherit parent FRU's label */ 225 (void) topo_node_fru_set(hbn, NULL, 0, &err); 226 (void) topo_node_label_set(hbn, NULL, &err); 227 228 /* Make room for children */ 229 (void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, CPUBOARD_MAX); 230 231 topo_mod_dprintf(mp, "cpuboard_hb_node_create: EXIT hbn=%p\n", hbn); 232 233 return (hbn); 234 } 235 236 /* 237 * Enumerate hostbridge on the cpuboard. Hostbridge and root complex instances 238 * match the cpuboard instance. 239 */ 240 int 241 cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, char *rcpath, 242 tnode_t *cpubn, int brd) 243 { 244 int hb; 245 int rc; 246 tnode_t *hbnode; 247 tnode_t *rcnode; 248 topo_mod_t *pcimod; 249 250 topo_mod_dprintf(mp, "cpuboard_hb_enum: brd: %d, cpubn=%p\n", 251 brd, cpubn); 252 253 /* Load the pcibus module. We'll need it later. */ 254 pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS); 255 if (pcimod == NULL) { 256 topo_mod_dprintf(mp, "can't load pcibus module: %s\n", 257 topo_strerror(topo_mod_errno(mp))); 258 return (-1); 259 } 260 hb = rc = brd; 261 262 /* The root complex exists! */ 263 topo_mod_dprintf(mp, "declaring " 264 "/motherboard=0/cpuboard=%d/hostbridge=%d/" 265 "pciexrc=%d\n", brd, hb, rc); 266 267 /* Create the hostbridge node */ 268 hbnode = cpuboard_hb_node_create(mp, cpubn, hb); 269 if (hbnode == NULL) { 270 topo_mod_dprintf(mp, 271 "unable to create hbnode: %s\n", 272 topo_strerror(topo_mod_errno(mp))); 273 topo_mod_unload(pcimod); 274 return (-1); 275 } 276 /* Create the root complex node */ 277 rcnode = cpuboard_rc_node_create(mp, hbnode, dnode, rcpath, rc); 278 if (rcnode == NULL) { 279 topo_mod_dprintf(mp, 280 "unable to create rcnode: %s\n", 281 topo_strerror(topo_mod_errno(mp))); 282 topo_mod_unload(pcimod); 283 return (-1); 284 } 285 /* 286 * If dnode not NULL, enumerate pcibus nodes under the root complex. 287 * If dnode NULL, skip enumeration. Condition could occur if the RC 288 * is assigned to non-control domain. 289 */ 290 if ((dnode != NULL) && topo_mod_enumerate(pcimod, rcnode, 291 PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) { 292 topo_mod_dprintf(mp, 293 "error enumerating pcibus: %s\n", 294 topo_strerror(topo_mod_errno(mp))); 295 topo_mod_unload(pcimod); 296 return (-1); 297 } 298 topo_mod_unload(pcimod); 299 return (0); 300 } 301