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 2007 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 <unistd.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <stdarg.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <limits.h> 36 #include <alloca.h> 37 #include <kstat.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <libnvpair.h> 41 #include <sys/types.h> 42 #include <sys/bitmap.h> 43 #include <sys/processor.h> 44 #include <sys/param.h> 45 #include <sys/fm/protocol.h> 46 #include <sys/systeminfo.h> 47 #include <sys/mc.h> 48 #include <sys/mc_amd.h> 49 #include <sys/mc_intel.h> 50 #include <fm/topo_mod.h> 51 52 #include "chip.h" 53 54 #ifndef MAX 55 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 56 #endif 57 58 static const topo_pgroup_info_t dimm_channel_pgroup = 59 { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 60 static const topo_pgroup_info_t dimm_pgroup = 61 { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 62 static const topo_pgroup_info_t rank_pgroup = 63 { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 64 static const topo_pgroup_info_t mc_pgroup = 65 { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 66 static const topo_method_t rank_methods[] = { 67 { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 68 TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 69 mem_asru_compute }, 70 { NULL } 71 }; 72 73 static const topo_method_t dimm_methods[] = { 74 { SIMPLE_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 75 simple_dimm_label}, 76 { SIMPLE_DIMM_LBL_MP, "Property method", 0, TOPO_STABILITY_INTERNAL, 77 simple_dimm_label_mp}, 78 { SEQ_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 79 seq_dimm_label}, 80 { NULL } 81 }; 82 83 static int mc_fd; 84 85 int 86 mc_offchip_open() 87 { 88 mc_fd = open("/dev/mc/mc", O_RDONLY); 89 return (mc_fd != -1); 90 } 91 92 void 93 mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm, 94 nvlist_t **ranks_nvp, int nranks, char *serial, char *part, char *rev) 95 { 96 int i; 97 int rank; 98 tnode_t *rnode; 99 nvpair_t *nvp; 100 nvlist_t *fmri; 101 int err = 0; 102 103 rank = dimm * 2; 104 if (topo_node_range_create(mod, dnode, RANK, rank, 105 rank + nranks - 1) < 0) { 106 whinge(mod, NULL, "mc_add_dimms: node range create failed" 107 " for rank\n"); 108 return; 109 } 110 for (i = 0; i < nranks; i++) { 111 fmri = topo_mod_hcfmri(mod, dnode, FM_HC_SCHEME_VERSION, 112 RANK, rank, NULL, auth, part, rev, serial); 113 if (fmri == NULL) { 114 whinge(mod, NULL, 115 "mc_add_ranks: topo_mod_hcfmri failed\n"); 116 return; 117 } 118 if ((rnode = topo_node_bind(mod, dnode, RANK, rank, 119 fmri)) == NULL) { 120 nvlist_free(fmri); 121 whinge(mod, NULL, "mc_add_ranks: node bind failed" 122 " for ranks\n"); 123 return; 124 } 125 (void) topo_node_fru_set(rnode, NULL, 0, &err); 126 127 if (topo_method_register(mod, rnode, rank_methods) < 0) 128 whinge(mod, &err, "rank_create: " 129 "topo_method_register failed"); 130 131 (void) topo_node_asru_set(rnode, fmri, TOPO_ASRU_COMPUTE, &err); 132 133 nvlist_free(fmri); 134 135 (void) topo_pgroup_create(rnode, &rank_pgroup, &err); 136 for (nvp = nvlist_next_nvpair(ranks_nvp[i], NULL); nvp != NULL; 137 nvp = nvlist_next_nvpair(ranks_nvp[i], nvp)) { 138 (void) nvprop_add(mod, nvp, PGNAME(RANK), rnode); 139 } 140 rank++; 141 } 142 } 143 144 static void 145 mc_add_dimms(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, 146 nvlist_t **nvl, uint_t ndimms) 147 { 148 int i; 149 nvlist_t *fmri; 150 tnode_t *dnode; 151 nvpair_t *nvp; 152 int err; 153 nvlist_t **ranks_nvp; 154 uint_t nranks = 0; 155 char *serial = NULL; 156 char *part = NULL; 157 char *rev = NULL; 158 char *label = NULL; 159 char *name; 160 161 if (topo_node_range_create(mod, pnode, DIMM, 0, ndimms-1) < 0) { 162 whinge(mod, NULL, 163 "mc_add_dimms: node range create failed\n"); 164 return; 165 } 166 for (i = 0; i < ndimms; i++) { 167 for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 168 nvp = nvlist_next_nvpair(nvl[i], nvp)) { 169 name = nvpair_name(nvp); 170 if (strcmp(name, MCINTEL_NVLIST_RANKS) == 0) { 171 (void) nvpair_value_nvlist_array(nvp, 172 &ranks_nvp, &nranks); 173 } else if (strcmp(name, FM_FMRI_HC_SERIAL_ID) == 0) { 174 (void) nvpair_value_string(nvp, &serial); 175 } else if (strcmp(name, FM_FMRI_HC_PART) == 0) { 176 (void) nvpair_value_string(nvp, &part); 177 } else if (strcmp(name, FM_FMRI_HC_REVISION) == 0) { 178 (void) nvpair_value_string(nvp, &rev); 179 } else if (strcmp(name, FM_FAULT_FRU_LABEL) == 0) { 180 (void) nvpair_value_string(nvp, &label); 181 } 182 } 183 fmri = NULL; 184 fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, 185 DIMM, i, NULL, auth, part, rev, serial); 186 if (fmri == NULL) { 187 whinge(mod, NULL, 188 "mc_add_dimms: topo_mod_hcfmri failed\n"); 189 return; 190 } 191 if ((dnode = topo_node_bind(mod, pnode, DIMM, i, 192 fmri)) == NULL) { 193 nvlist_free(fmri); 194 whinge(mod, NULL, "mc_add_dimms: node bind failed" 195 " for dimm\n"); 196 return; 197 } 198 199 if (topo_method_register(mod, dnode, dimm_methods) < 0) 200 whinge(mod, NULL, "mc_add_dimms: " 201 "topo_method_register failed"); 202 203 (void) topo_node_fru_set(dnode, fmri, 0, &err); 204 nvlist_free(fmri); 205 (void) topo_pgroup_create(dnode, &dimm_pgroup, &err); 206 207 for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 208 nvp = nvlist_next_nvpair(nvl[i], nvp)) { 209 name = nvpair_name(nvp); 210 if (strcmp(name, MCINTEL_NVLIST_RANKS) != 0 && 211 strcmp(name, FM_FAULT_FRU_LABEL) != 0) { 212 (void) nvprop_add(mod, nvp, PGNAME(DIMM), 213 dnode); 214 } 215 } 216 if (label) 217 (void) topo_node_label_set(dnode, label, &err); 218 219 if (nranks) { 220 mc_add_ranks(mod, dnode, auth, i, ranks_nvp, nranks, 221 serial, part, rev); 222 } 223 } 224 } 225 226 static int 227 mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth, 228 nvlist_t *nvl) 229 { 230 tnode_t *mc_channel; 231 nvlist_t *fmri; 232 nvlist_t **dimm_nvl; 233 uint_t ndimms; 234 int err; 235 236 if (mkrsrc(mod, pnode, DRAMCHANNEL, channel, auth, &fmri) != 0) { 237 whinge(mod, NULL, "mc_add_channel: mkrsrc failed\n"); 238 return (-1); 239 } 240 if ((mc_channel = topo_node_bind(mod, pnode, DRAMCHANNEL, channel, 241 fmri)) == NULL) { 242 whinge(mod, NULL, "mc_add_channel: node bind failed for %s\n", 243 DRAMCHANNEL); 244 nvlist_free(fmri); 245 return (-1); 246 } 247 (void) topo_node_fru_set(mc_channel, NULL, 0, &err); 248 nvlist_free(fmri); 249 (void) topo_pgroup_create(mc_channel, &dimm_channel_pgroup, &err); 250 if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_DIMMS, &dimm_nvl, 251 &ndimms) == 0) { 252 mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms); 253 } 254 return (0); 255 } 256 257 static int 258 mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth, 259 nvlist_t *nvl) 260 { 261 int err; 262 int i, j; 263 int channel; 264 int nmc; 265 tnode_t *mcnode; 266 nvlist_t *fmri; 267 nvlist_t **channel_nvl; 268 uint_t nchannels; 269 270 if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_MC, &channel_nvl, 271 &nchannels) != 0) { 272 whinge(mod, NULL, 273 "mc_nb_create: failed to find channel information\n"); 274 return (-1); 275 } 276 nmc = nchannels / 2; 277 if (topo_node_range_create(mod, pnode, name, 0, nmc-1) < 0) { 278 whinge(mod, NULL, 279 "mc_nb_create: node range create failed\n"); 280 return (-1); 281 } 282 channel = 0; 283 for (i = 0; i < nmc; i++) { 284 if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 285 whinge(mod, NULL, "mc_nb_create: mkrsrc failed\n"); 286 return (-1); 287 } 288 if ((mcnode = topo_node_bind(mod, pnode, name, i, 289 fmri)) == NULL) { 290 whinge(mod, NULL, "chip_create: node bind failed" 291 " for memory-controller\n"); 292 nvlist_free(fmri); 293 return (-1); 294 } 295 296 (void) topo_node_fru_set(mcnode, NULL, 0, &err); 297 nvlist_free(fmri); 298 (void) topo_pgroup_create(mcnode, &mc_pgroup, &err); 299 300 if (topo_node_range_create(mod, mcnode, DRAMCHANNEL, channel, 301 channel + 1) < 0) { 302 whinge(mod, NULL, 303 "mc_nb_create: channel node range create failed\n"); 304 return (-1); 305 } 306 for (j = 0; j < 2; j++) { 307 if (mc_add_channel(mod, mcnode, channel, auth, 308 channel_nvl[channel]) < 0) { 309 return (-1); 310 } 311 channel++; 312 } 313 } 314 315 return (NULL); 316 } 317 318 int 319 mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 320 nvlist_t *auth) 321 { 322 mc_snapshot_info_t mcs; 323 void *buf = NULL; 324 nvlist_t *nvl; 325 uint8_t ver; 326 int rc; 327 328 if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 329 (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 330 ioctl(mc_fd, MC_IOC_SNAPSHOT, buf) == -1) { 331 332 whinge(mod, NULL, "mc failed to snapshot %s\n", 333 strerror(errno)); 334 335 free(buf); 336 (void) close(mc_fd); 337 return (NULL); 338 } 339 (void) close(mc_fd); 340 (void) nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 341 topo_mod_free(mod, buf, mcs.mcs_size); 342 343 if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_VERSTR, &ver) != 0) { 344 whinge(mod, NULL, "mc nvlist is not versioned\n"); 345 nvlist_free(nvl); 346 return (NULL); 347 } else if (ver != MCINTEL_NVLIST_VERS0) { 348 whinge(mod, NULL, "mc nvlist version mismatch\n"); 349 nvlist_free(nvl); 350 return (NULL); 351 } 352 353 rc = mc_nb_create(mod, pnode, name, auth, nvl); 354 355 nvlist_free(nvl); 356 return (rc); 357 } 358