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 <sys/types.h> 30 #include <sys/time.h> 31 #include <sys/nvpair.h> 32 #include <sys/cmn_err.h> 33 #include <sys/cred.h> 34 #include <sys/open.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/conf.h> 38 #include <sys/modctl.h> 39 #include <sys/cyclic.h> 40 #include <sys/errorq.h> 41 #include <sys/stat.h> 42 #include <sys/cpuvar.h> 43 #include <sys/mc_intel.h> 44 #include <sys/mc.h> 45 #include <sys/fm/protocol.h> 46 #include "nb_log.h" 47 #include "nb5000.h" 48 49 char _depends_on[] = "drv/smbios"; 50 51 nvlist_t *inb_mc_nvl; 52 krwlock_t inb_mc_lock; 53 54 char *inb_mc_snapshot; 55 uint_t nb_config_gen; 56 uint_t inb_mc_snapshotgen; 57 size_t inb_mc_snapshotsz; 58 static dev_info_t *inb_dip; 59 int nb_allow_detach = 0; 60 61 static uint64_t 62 rank_to_base(uint8_t branch, uint8_t rank, uint8_t *interleave, uint64_t *limit, 63 uint64_t *hole_base, uint64_t *hole_size, uint8_t *wayp, 64 uint8_t *branch_interleavep) 65 { 66 uint8_t i, j; 67 uint64_t base = 0; 68 uint64_t lt = 0; 69 uint64_t h = 0; 70 uint64_t hs = 0; 71 uint8_t il = 1; 72 uint8_t way = 0; 73 uint8_t branch_interleave = 0; 74 75 for (i = 0; i < NB_MEM_RANK_SELECT; i++) { 76 for (j = 0; j < NB_RANKS_IN_SELECT; j++) { 77 if (nb_ranks[branch][i].rank[j] == rank) { 78 base = nb_ranks[branch][i].base; 79 lt = nb_ranks[branch][i].limit; 80 il = nb_ranks[branch][i].interleave; 81 h = nb_ranks[branch][i].hole_base; 82 hs = nb_ranks[branch][i].hole_size; 83 way = j; 84 branch_interleave = 85 nb_ranks[branch][i].branch_interleave; 86 i = NB_MEM_RANK_SELECT; 87 break; 88 } 89 } 90 } 91 if (lt == 0) { 92 for (i = 0; lt == 0 && i < NB_MEM_BRANCH_SELECT; i++) { 93 if (nb_banks[i].way[branch] && 94 base >= nb_banks[i].base && 95 base < nb_banks[i].base + nb_banks[i].limit) { 96 lt = nb_banks[i].limit; 97 break; 98 } 99 } 100 } 101 *interleave = il; 102 *limit = lt; 103 *hole_base = h; 104 *hole_size = hs; 105 *wayp = way; 106 *branch_interleavep = branch_interleave; 107 return (base); 108 } 109 110 void 111 inb_rank(nvlist_t *newdimm, nb_dimm_t *nb_dimm, uint8_t channel, uint32_t dimm) 112 { 113 nvlist_t **newrank; 114 int i; 115 116 newrank = kmem_zalloc(sizeof (nvlist_t *) * nb_dimm->nranks, KM_SLEEP); 117 for (i = 0; i < nb_dimm->nranks; i++) { 118 uint64_t dimm_base; 119 uint64_t limit; 120 uint8_t interleave; 121 uint8_t way; 122 uint8_t branch_interleave; 123 uint64_t hole_base; 124 uint64_t hole_size; 125 126 dimm_base = rank_to_base(channel/2, dimm*2 + i, &interleave, 127 &limit, &hole_base, &hole_size, &way, &branch_interleave); 128 (void) nvlist_alloc(&newrank[i], NV_UNIQUE_NAME, KM_SLEEP); 129 130 (void) nvlist_add_uint64(newrank[i], "dimm-rank-base", 131 dimm_base); 132 if (hole_size) { 133 (void) nvlist_add_uint64(newrank[i], "dimm-hole", 134 hole_base); 135 (void) nvlist_add_uint64(newrank[i], "dimm-hole-size", 136 hole_size); 137 } 138 (void) nvlist_add_uint64(newrank[i], "dimm-rank-limit", 139 limit); 140 if (interleave > 1) { 141 (void) nvlist_add_uint32(newrank[i], 142 "dimm-rank-interleave", (uint32_t)interleave); 143 (void) nvlist_add_uint32(newrank[i], 144 "dimm-rank-interleave-way", (uint32_t)way); 145 if (branch_interleave) { 146 (void) nvlist_add_uint32(newrank[i], 147 "dimm-rank-interleave-branch", (uint32_t)1); 148 } 149 } 150 } 151 (void) nvlist_add_nvlist_array(newdimm, MCINTEL_NVLIST_RANKS, newrank, 152 nb_dimm->nranks); 153 kmem_free(newrank, sizeof (nvlist_t *) * nb_dimm->nranks); 154 } 155 156 nvlist_t * 157 inb_dimm(nb_dimm_t *nb_dimm, uint8_t channel, uint32_t dimm) 158 { 159 nvlist_t *newdimm; 160 uint8_t t; 161 char sbuf[65]; 162 163 (void) nvlist_alloc(&newdimm, NV_UNIQUE_NAME, KM_SLEEP); 164 (void) nvlist_add_uint32(newdimm, "dimm-number", dimm); 165 166 if (nb_dimm->dimm_size >= 1024*1024*1024) { 167 (void) snprintf(sbuf, sizeof (sbuf), "%dG", 168 (int)(nb_dimm->dimm_size / (1024*1024*1024))); 169 } else { 170 (void) snprintf(sbuf, sizeof (sbuf), "%dM", 171 (int)(nb_dimm->dimm_size / (1024*1024))); 172 } 173 (void) nvlist_add_string(newdimm, "dimm-size", sbuf); 174 (void) nvlist_add_uint32(newdimm, "nbanks", (uint32_t)nb_dimm->nbanks); 175 (void) nvlist_add_uint32(newdimm, "ncolumn", 176 (uint32_t)nb_dimm->ncolumn); 177 (void) nvlist_add_uint32(newdimm, "nrow", (uint32_t)nb_dimm->nrow); 178 (void) nvlist_add_uint32(newdimm, "width", (uint32_t)nb_dimm->width); 179 (void) nvlist_add_uint32(newdimm, "ranks", (uint32_t)nb_dimm->nranks); 180 inb_rank(newdimm, nb_dimm, channel, dimm); 181 (void) nvlist_add_uint32(newdimm, "manufacture-id", 182 (uint32_t)nb_dimm->manufacture_id); 183 (void) nvlist_add_uint32(newdimm, "manufacture-location", 184 (uint32_t)nb_dimm->manufacture_location); 185 (void) nvlist_add_uint32(newdimm, "manufacture-week", 186 (uint32_t)nb_dimm->manufacture_week); 187 (void) nvlist_add_uint32(newdimm, "manufacture-year", 188 (uint32_t)nb_dimm->manufacture_year + 2000); 189 /* create Sun Serial number from SPD data */ 190 (void) snprintf(sbuf, sizeof (sbuf), "%04x%02x%02x%02x%08x", 191 (uint32_t)nb_dimm->manufacture_id & 0x7fff, 192 (uint32_t)nb_dimm->manufacture_location, 193 (uint32_t)nb_dimm->manufacture_year, 194 (uint32_t)nb_dimm->manufacture_week, 195 nb_dimm->serial_number); 196 (void) nvlist_add_string(newdimm, FM_FMRI_HC_SERIAL_ID, sbuf); 197 if (nb_dimm->part_number && nb_dimm->part_number[0]) { 198 t = sizeof (nb_dimm->part_number); 199 (void) strncpy(sbuf, nb_dimm->part_number, t); 200 sbuf[t] = 0; 201 (void) nvlist_add_string(newdimm, FM_FMRI_HC_PART, sbuf); 202 } 203 if (nb_dimm->revision && nb_dimm->revision[0]) { 204 t = sizeof (nb_dimm->revision); 205 (void) strncpy(sbuf, nb_dimm->revision, t); 206 sbuf[t] = 0; 207 (void) nvlist_add_string(newdimm, FM_FMRI_HC_REVISION, sbuf); 208 } 209 t = sizeof (nb_dimm->label); 210 (void) strncpy(sbuf, nb_dimm->label, t); 211 sbuf[t] = 0; 212 (void) nvlist_add_string(newdimm, FM_FAULT_FRU_LABEL, sbuf); 213 return (newdimm); 214 } 215 216 static void 217 inb_dimmlist(nvlist_t *nvl) 218 { 219 nvlist_t **dimmlist; 220 nvlist_t **newchannel; 221 int nchannels = nb_number_memory_controllers * 2; 222 int nd; 223 uint8_t i, j; 224 nb_dimm_t **dimmpp; 225 nb_dimm_t *dimmp; 226 227 dimmlist = kmem_zalloc(sizeof (nvlist_t *) * nb_dimms_per_channel, 228 KM_SLEEP); 229 newchannel = kmem_zalloc(sizeof (nvlist_t *) * nchannels, KM_SLEEP); 230 dimmpp = nb_dimms; 231 for (i = 0; i < nchannels; i++) { 232 (void) nvlist_alloc(&newchannel[i], NV_UNIQUE_NAME, KM_SLEEP); 233 nd = 0; 234 for (j = 0; j < nb_dimms_per_channel; j++) { 235 dimmp = *dimmpp; 236 if (dimmp != NULL) { 237 dimmlist[nd] = inb_dimm(dimmp, i, (uint32_t)j); 238 nd++; 239 } 240 dimmpp++; 241 } 242 if (nd) { 243 (void) nvlist_add_nvlist_array(newchannel[i], 244 "memory-dimms", dimmlist, nd); 245 for (j = 0; j < nd; j++) 246 nvlist_free(dimmlist[j]); 247 } 248 } 249 (void) nvlist_add_nvlist_array(nvl, MCINTEL_NVLIST_MC, newchannel, 250 nchannels); 251 kmem_free(dimmlist, sizeof (nvlist_t *) * nb_dimms_per_channel); 252 kmem_free(newchannel, sizeof (nvlist_t *) * nchannels); 253 } 254 255 static char * 256 inb_mc_name() 257 { 258 char *mc; 259 260 switch (nb_chipset) { 261 case INTEL_NB_7300: 262 mc = "Intel 7300"; 263 break; 264 case INTEL_NB_5000P: 265 mc = "Intel 5000P"; 266 break; 267 case INTEL_NB_5000V: 268 mc = "Intel 5000V"; 269 break; 270 case INTEL_NB_5000X: 271 mc = "Intel 5000X"; 272 break; 273 case INTEL_NB_5000Z: 274 mc = "Intel 5000Z"; 275 break; 276 default: 277 mc = "Intel 5000"; 278 break; 279 } 280 return (mc); 281 } 282 283 static void 284 inb_create_nvl() 285 { 286 nvlist_t *nvl; 287 288 (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 289 (void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_VERSTR, 290 MCINTEL_NVLIST_VERS); 291 (void) nvlist_add_string(nvl, "memory-controller", inb_mc_name()); 292 inb_dimmlist(nvl); 293 294 if (inb_mc_nvl) 295 nvlist_free(inb_mc_nvl); 296 inb_mc_nvl = nvl; 297 } 298 299 static void 300 inb_mc_snapshot_destroy() 301 { 302 ASSERT(RW_LOCK_HELD(&inb_mc_lock)); 303 304 if (inb_mc_snapshot == NULL) 305 return; 306 307 kmem_free(inb_mc_snapshot, inb_mc_snapshotsz); 308 inb_mc_snapshot = NULL; 309 inb_mc_snapshotsz = 0; 310 inb_mc_snapshotgen++; 311 } 312 313 static int 314 inb_mc_snapshot_update() 315 { 316 ASSERT(RW_LOCK_HELD(&inb_mc_lock)); 317 318 if (inb_mc_snapshot != NULL) 319 return (0); 320 321 if (nvlist_pack(inb_mc_nvl, &inb_mc_snapshot, &inb_mc_snapshotsz, 322 NV_ENCODE_XDR, KM_SLEEP) != 0) 323 return (-1); 324 325 return (0); 326 } 327 328 /*ARGSUSED*/ 329 static int 330 inb_mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 331 int *rvalp) 332 { 333 int rc = 0; 334 mc_snapshot_info_t mcs; 335 336 if (cmd != MC_IOC_SNAPSHOT_INFO && cmd != MC_IOC_SNAPSHOT) 337 return (EINVAL); 338 339 rw_enter(&inb_mc_lock, RW_READER); 340 if (inb_mc_nvl == NULL || inb_mc_snapshotgen != nb_config_gen) { 341 if (!rw_tryupgrade(&inb_mc_lock)) { 342 rw_exit(&inb_mc_lock); 343 return (EAGAIN); 344 } 345 if (inb_mc_nvl) 346 inb_mc_snapshot_destroy(); 347 inb_create_nvl(); 348 nb_config_gen = inb_mc_snapshotgen; 349 (void) inb_mc_snapshot_update(); 350 } 351 switch (cmd) { 352 case MC_IOC_SNAPSHOT_INFO: 353 mcs.mcs_size = (uint32_t)inb_mc_snapshotsz; 354 mcs.mcs_gen = inb_mc_snapshotgen; 355 356 if (ddi_copyout(&mcs, (void *)arg, sizeof (mc_snapshot_info_t), 357 mode) < 0) 358 rc = EFAULT; 359 break; 360 case MC_IOC_SNAPSHOT: 361 if (ddi_copyout(inb_mc_snapshot, (void *)arg, inb_mc_snapshotsz, 362 mode) < 0) 363 rc = EFAULT; 364 break; 365 } 366 rw_exit(&inb_mc_lock); 367 return (rc); 368 } 369 370 /*ARGSUSED*/ 371 static int 372 inb_mc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 373 void **result) 374 { 375 if ((infocmd != DDI_INFO_DEVT2DEVINFO && 376 infocmd != DDI_INFO_DEVT2INSTANCE) || inb_dip == NULL) { 377 *result = NULL; 378 return (DDI_FAILURE); 379 } 380 if (infocmd == DDI_INFO_DEVT2DEVINFO) 381 *result = inb_dip; 382 else 383 *result = (void *)(uintptr_t)ddi_get_instance(inb_dip); 384 return (0); 385 } 386 387 static int 388 inb_mc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 389 { 390 if (cmd == DDI_RESUME) { 391 nb_dev_reinit(); 392 return (DDI_SUCCESS); 393 } 394 if (cmd != DDI_ATTACH) 395 return (DDI_FAILURE); 396 if (inb_dip == NULL) { 397 inb_dip = dip; 398 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model", 399 inb_mc_name()); 400 nb_pci_cfg_setup(dip); 401 if (nb_dev_init()) { 402 nb_pci_cfg_free(); 403 inb_dip = NULL; 404 return (DDI_FAILURE); 405 } 406 if (ddi_create_minor_node(dip, "mc-intel", S_IFCHR, 0, 407 "ddi_mem_ctrl", 0) != DDI_SUCCESS) { 408 cmn_err(CE_WARN, "failed to create minor node" 409 " for memory controller\n"); 410 } 411 cmi_hdl_walk(inb_mc_register, NULL, NULL, NULL); 412 } 413 414 return (DDI_SUCCESS); 415 } 416 417 /*ARGSUSED*/ 418 static int 419 inb_mc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 420 { 421 if (nb_allow_detach && cmd == DDI_DETACH && dip == inb_dip) { 422 rw_enter(&inb_mc_lock, RW_WRITER); 423 inb_mc_snapshot_destroy(); 424 rw_exit(&inb_mc_lock); 425 inb_dip = NULL; 426 return (DDI_SUCCESS); 427 } else if (cmd == DDI_SUSPEND || cmd == DDI_PM_SUSPEND) { 428 return (DDI_SUCCESS); 429 } else { 430 return (DDI_FAILURE); 431 } 432 } 433 434 /*ARGSUSED*/ 435 static int 436 inb_mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 437 { 438 if (otyp != OTYP_CHR) 439 return (EINVAL); 440 441 rw_enter(&inb_mc_lock, RW_READER); 442 if (getminor(*devp) >= 1) { 443 rw_exit(&inb_mc_lock); 444 return (EINVAL); 445 } 446 rw_exit(&inb_mc_lock); 447 448 return (0); 449 } 450 451 /*ARGSUSED*/ 452 static int 453 inb_mc_close(dev_t dev, int flag, int otyp, cred_t *credp) 454 { 455 return (0); 456 } 457 458 459 static struct cb_ops inb_mc_cb_ops = { 460 inb_mc_open, 461 inb_mc_close, 462 nodev, /* not a block driver */ 463 nodev, /* no print routine */ 464 nodev, /* no dump routine */ 465 nodev, /* no read routine */ 466 nodev, /* no write routine */ 467 inb_mc_ioctl, 468 nodev, /* no devmap routine */ 469 nodev, /* no mmap routine */ 470 nodev, /* no segmap routine */ 471 nochpoll, /* no chpoll routine */ 472 ddi_prop_op, 473 0, /* not a STREAMS driver */ 474 D_NEW | D_MP, /* safe for multi-thread/multi-processor */ 475 }; 476 477 static struct dev_ops inb_mc_ops = { 478 DEVO_REV, /* devo_rev */ 479 0, /* devo_refcnt */ 480 inb_mc_getinfo, /* devo_getinfo */ 481 nulldev, /* devo_identify */ 482 nulldev, /* devo_probe */ 483 inb_mc_attach, /* devo_attach */ 484 inb_mc_detach, /* devo_detach */ 485 nodev, /* devo_reset */ 486 &inb_mc_cb_ops, /* devo_cb_ops */ 487 NULL, /* devo_bus_ops */ 488 NULL /* devo_power */ 489 }; 490 491 static struct modldrv modldrv = { 492 &mod_driverops, 493 "Intel 5000 Memory Controller Hub Module", 494 &inb_mc_ops 495 }; 496 497 static struct modlinkage modlinkage = { 498 MODREV_1, 499 (void *)&modldrv, 500 NULL 501 }; 502 503 int 504 _init(void) 505 { 506 int err; 507 508 err = nb_init(); 509 if (err == 0 && (err = mod_install(&modlinkage)) == 0) 510 rw_init(&inb_mc_lock, NULL, RW_DRIVER, NULL); 511 512 return (err); 513 } 514 515 int 516 _info(struct modinfo *modinfop) 517 { 518 return (mod_info(&modlinkage, modinfop)); 519 } 520 521 int 522 _fini(void) 523 { 524 int err; 525 526 if ((err = mod_remove(&modlinkage)) == 0) { 527 nb_unload(); 528 rw_destroy(&inb_mc_lock); 529 } 530 531 return (err); 532 } 533