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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Intel model-specific support. Right now all this conists of is 28 * to modify the ereport subclass to produce different ereport classes 29 * so that we can have different diagnosis rules and corresponding faults. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/cmn_err.h> 34 #include <sys/modctl.h> 35 #include <sys/mca_x86.h> 36 #include <sys/cpu_module_ms_impl.h> 37 #include <sys/mc_intel.h> 38 #include <sys/pci_cfgspace.h> 39 #include <sys/fm/protocol.h> 40 #include <sys/fm/util.h> 41 #include <sys/fm/smb/fmsmb.h> 42 43 extern int x86gentopo_legacy; 44 45 int gintel_ms_support_disable = 0; 46 int gintel_error_action_return = 0; 47 int gintel_ms_unconstrained = 0; 48 49 int quickpath; 50 int max_bus_number = 0xff; 51 52 #define ERR_COUNTER_INDEX 2 53 #define MAX_CPU_NODES 2 54 #define N_MC_COR_ECC_CNT 6 55 uint32_t err_counter_array[MAX_CPU_NODES][ERR_COUNTER_INDEX][N_MC_COR_ECC_CNT]; 56 uint8_t err_counter_index[MAX_CPU_NODES]; 57 58 #define MAX_BUS_NUMBER max_bus_number 59 #define SOCKET_BUS(cpu) (MAX_BUS_NUMBER - (cpu)) 60 61 #define MC_COR_ECC_CNT(chipid, reg) (*pci_getl_func)(SOCKET_BUS(chipid), \ 62 NEHALEM_EP_MEMORY_CONTROLLER_DEV, NEHALEM_EP_MEMORY_CONTROLLER_FUNC, \ 63 0x80 + (reg) * 4) 64 65 #define MSCOD_MEM_ECC_READ 0x1 66 #define MSCOD_MEM_ECC_SCRUB 0x2 67 #define MSCOD_MEM_WR_PARITY 0x4 68 #define MSCOD_MEM_REDUNDANT_MEM 0x8 69 #define MSCOD_MEM_SPARE_MEM 0x10 70 #define MSCOD_MEM_ILLEGAL_ADDR 0x20 71 #define MSCOD_MEM_BAD_ID 0x40 72 #define MSCOD_MEM_ADDR_PARITY 0x80 73 #define MSCOD_MEM_BYTE_PARITY 0x100 74 75 #define GINTEL_ERROR_MEM 0x1000 76 #define GINTEL_ERROR_QUICKPATH 0x2000 77 #define GINTEL_ERROR_UNKNOWN 0x4000 78 79 #define GINTEL_ERR_SPARE_MEM (GINTEL_ERROR_MEM | 1) 80 #define GINTEL_ERR_MEM_UE (GINTEL_ERROR_MEM | 2) 81 #define GINTEL_ERR_MEM_CE (GINTEL_ERROR_MEM | 3) 82 #define GINTEL_ERR_MEM_PARITY (GINTEL_ERROR_MEM | 4) 83 #define GINTEL_ERR_MEM_ADDR_PARITY (GINTEL_ERROR_MEM | 5) 84 #define GINTEL_ERR_MEM_REDUNDANT (GINTEL_ERROR_MEM | 6) 85 #define GINTEL_ERR_MEM_BAD_ADDR (GINTEL_ERROR_MEM | 7) 86 #define GINTEL_ERR_MEM_BAD_ID (GINTEL_ERROR_MEM | 8) 87 #define GINTEL_ERR_MEM_UNKNOWN (GINTEL_ERROR_MEM | 0xfff) 88 89 #define MSR_MC_MISC_MEM_CHANNEL_MASK 0x00000000000c0000ULL 90 #define MSR_MC_MISC_MEM_CHANNEL_SHIFT 18 91 #define MSR_MC_MISC_MEM_DIMM_MASK 0x0000000000030000ULL 92 #define MSR_MC_MISC_MEM_DIMM_SHIFT 16 93 #define MSR_MC_MISC_MEM_SYNDROME_MASK 0xffffffff00000000ULL 94 #define MSR_MC_MISC_MEM_SYNDROME_SHIFT 32 95 96 #define CPU_GENERATION_DONT_CARE 0 97 #define CPU_GENERATION_NEHALEM_EP 1 98 99 #define INTEL_CPU_6_ID 0x6 100 #define INTEL_NEHALEM_CPU_FAMILY_ID 0x6 101 #define INTEL_NEHALEM_CPU_MODEL_ID 0x1A 102 103 #define NEHALEM_EP_MEMORY_CONTROLLER_DEV 0x3 104 #define NEHALEM_EP_MEMORY_CONTROLLER_FUNC 0x2 105 106 /*ARGSUSED*/ 107 int 108 gintel_init(cmi_hdl_t hdl, void **datap) 109 { 110 uint32_t nb_chipset; 111 112 if (gintel_ms_support_disable) 113 return (ENOTSUP); 114 115 if (!is_x86_feature(x86_featureset, X86FSET_MCA)) 116 return (ENOTSUP); 117 118 nb_chipset = (*pci_getl_func)(0, 0, 0, 0x0); 119 switch (nb_chipset) { 120 case INTEL_NB_7300: 121 case INTEL_NB_5000P: 122 case INTEL_NB_5000X: 123 case INTEL_NB_5000V: 124 case INTEL_NB_5000Z: 125 case INTEL_NB_5400: 126 case INTEL_NB_5400A: 127 case INTEL_NB_5400B: 128 if (!gintel_ms_unconstrained) 129 gintel_error_action_return |= CMS_ERRSCOPE_POISONED; 130 break; 131 case INTEL_QP_IO: 132 case INTEL_QP_WP: 133 case INTEL_QP_36D: 134 case INTEL_QP_24D: 135 case INTEL_QP_U1: 136 case INTEL_QP_U2: 137 case INTEL_QP_U3: 138 case INTEL_QP_U4: 139 case INTEL_QP_JF: 140 case INTEL_QP_JF0: 141 case INTEL_QP_JF1: 142 case INTEL_QP_JF2: 143 case INTEL_QP_JF3: 144 case INTEL_QP_JF4: 145 case INTEL_QP_JF5: 146 case INTEL_QP_JF6: 147 case INTEL_QP_JF7: 148 case INTEL_QP_JF8: 149 case INTEL_QP_JF9: 150 case INTEL_QP_JFa: 151 case INTEL_QP_JFb: 152 case INTEL_QP_JFc: 153 case INTEL_QP_JFd: 154 case INTEL_QP_JFe: 155 case INTEL_QP_JFf: 156 quickpath = 1; 157 break; 158 default: 159 break; 160 } 161 return (0); 162 } 163 164 /*ARGSUSED*/ 165 uint32_t 166 gintel_error_action(cmi_hdl_t hdl, int ismc, int bank, 167 uint64_t status, uint64_t addr, uint64_t misc, void *mslogout) 168 { 169 uint32_t rc; 170 171 if (ismc == 0 && bank == 0 && 172 cmi_hdl_family(hdl) == INTEL_CPU_6_ID && 173 cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID && 174 MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && 175 MCAX86_MSERRCODE(status) == 0) { 176 rc = CMS_ERRSCOPE_CURCONTEXT_OK | CMS_ERRSCOPE_CLEARED_UC; 177 } else if ((status & MSR_MC_STATUS_PCC) == 0) { 178 rc = gintel_error_action_return; 179 } else { 180 rc = gintel_error_action_return & ~CMS_ERRSCOPE_POISONED; 181 } 182 return (rc); 183 } 184 185 /*ARGSUSED*/ 186 cms_cookie_t 187 gintel_disp_match(cmi_hdl_t hdl, int ismc, int bank, uint64_t status, 188 uint64_t addr, uint64_t misc, void *mslogout) 189 { 190 cms_cookie_t rt = (cms_cookie_t)NULL; 191 uint16_t mcacode = MCAX86_ERRCODE(status); 192 uint16_t mscode = MCAX86_MSERRCODE(status); 193 194 if (MCAX86_ERRCODE_ISMEMORY_CONTROLLER(mcacode)) { 195 /* 196 * memory controller errors 197 */ 198 if (mscode & MSCOD_MEM_SPARE_MEM) { 199 rt = (cms_cookie_t)GINTEL_ERR_SPARE_MEM; 200 } else if (mscode & (MSCOD_MEM_ECC_READ | 201 MSCOD_MEM_ECC_SCRUB)) { 202 if (status & MSR_MC_STATUS_UC) 203 rt = (cms_cookie_t)GINTEL_ERR_MEM_UE; 204 else 205 rt = (cms_cookie_t)GINTEL_ERR_MEM_CE; 206 } else if (mscode & (MSCOD_MEM_WR_PARITY | 207 MSCOD_MEM_BYTE_PARITY)) { 208 rt = (cms_cookie_t)GINTEL_ERR_MEM_PARITY; 209 } else if (mscode & MSCOD_MEM_ADDR_PARITY) { 210 rt = (cms_cookie_t)GINTEL_ERR_MEM_ADDR_PARITY; 211 } else if (mscode & MSCOD_MEM_REDUNDANT_MEM) { 212 rt = (cms_cookie_t)GINTEL_ERR_MEM_REDUNDANT; 213 } else if (mscode & MSCOD_MEM_ILLEGAL_ADDR) { 214 rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ADDR; 215 } else if (mscode & MSCOD_MEM_BAD_ID) { 216 rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ID; 217 } else { 218 rt = (cms_cookie_t)GINTEL_ERR_MEM_UNKNOWN; 219 } 220 } else if (quickpath && 221 MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status))) { 222 rt = (cms_cookie_t)GINTEL_ERROR_QUICKPATH; 223 } else if (ismc == 0 && bank == 0 && 224 cmi_hdl_family(hdl) == INTEL_CPU_6_ID && 225 cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID && 226 MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && 227 MCAX86_MSERRCODE(status) == 0) { 228 rt = (cms_cookie_t)GINTEL_ERROR_UNKNOWN; 229 } 230 return (rt); 231 } 232 233 /*ARGSUSED*/ 234 void 235 gintel_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie, 236 const char **cpuclsp, const char **leafclsp) 237 { 238 *cpuclsp = FM_EREPORT_CPU_INTEL; 239 switch ((uintptr_t)mscookie) { 240 case GINTEL_ERROR_QUICKPATH: 241 *leafclsp = "quickpath.interconnect"; 242 break; 243 case GINTEL_ERR_SPARE_MEM: 244 *leafclsp = "quickpath.mem_spare"; 245 break; 246 case GINTEL_ERR_MEM_UE: 247 *leafclsp = "quickpath.mem_ue"; 248 break; 249 case GINTEL_ERR_MEM_CE: 250 *leafclsp = "quickpath.mem_ce"; 251 break; 252 case GINTEL_ERR_MEM_PARITY: 253 *leafclsp = "quickpath.mem_parity"; 254 break; 255 case GINTEL_ERR_MEM_ADDR_PARITY: 256 *leafclsp = "quickpath.mem_addr_parity"; 257 break; 258 case GINTEL_ERR_MEM_REDUNDANT: 259 *leafclsp = "quickpath.mem_redundant"; 260 break; 261 case GINTEL_ERR_MEM_BAD_ADDR: 262 *leafclsp = "quickpath.mem_bad_addr"; 263 break; 264 case GINTEL_ERR_MEM_BAD_ID: 265 *leafclsp = "quickpath.mem_bad_id"; 266 break; 267 case GINTEL_ERR_MEM_UNKNOWN: 268 *leafclsp = "quickpath.mem_unknown"; 269 break; 270 case GINTEL_ERROR_UNKNOWN: 271 *leafclsp = "unknown"; 272 break; 273 } 274 } 275 276 static nvlist_t * 277 gintel_gentopo_ereport_detector(cmi_hdl_t hdl, cms_cookie_t mscookie, 278 nv_alloc_t *nva) 279 { 280 nvlist_t *nvl = (nvlist_t *)NULL; 281 nvlist_t *board_list = (nvlist_t *)NULL; 282 283 if (mscookie) { 284 board_list = cmi_hdl_smb_bboard(hdl); 285 286 if (board_list == NULL) 287 return (NULL); 288 289 if ((nvl = fm_nvlist_create(nva)) == NULL) 290 return (NULL); 291 292 if ((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) { 293 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, 294 NULL, NULL, board_list, 1, 295 "chip", cmi_hdl_smb_chipid(hdl)); 296 } else { 297 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, 298 NULL, NULL, board_list, 2, 299 "chip", cmi_hdl_smb_chipid(hdl), 300 "memory-controller", 0); 301 } 302 } 303 return (nvl); 304 } 305 306 /*ARGSUSED*/ 307 nvlist_t * 308 gintel_ereport_detector(cmi_hdl_t hdl, int bankno, cms_cookie_t mscookie, 309 nv_alloc_t *nva) 310 { 311 nvlist_t *nvl = (nvlist_t *)NULL; 312 313 if (!x86gentopo_legacy) { 314 nvl = gintel_gentopo_ereport_detector(hdl, mscookie, nva); 315 return (nvl); 316 } 317 318 if (mscookie) { 319 if ((nvl = fm_nvlist_create(nva)) == NULL) 320 return (NULL); 321 if (((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) || 322 ((uintptr_t)mscookie & GINTEL_ERROR_UNKNOWN)) { 323 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 2, 324 "motherboard", 0, 325 "chip", cmi_hdl_chipid(hdl)); 326 } else { 327 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3, 328 "motherboard", 0, 329 "chip", cmi_hdl_chipid(hdl), 330 "memory-controller", 0); 331 } 332 } 333 return (nvl); 334 } 335 336 static nvlist_t * 337 gintel_gentopo_ereport_create_resource_elem(cmi_hdl_t hdl, nv_alloc_t *nva, 338 mc_unum_t *unump) 339 { 340 nvlist_t *nvl, *snvl; 341 nvlist_t *board_list = NULL; 342 343 board_list = cmi_hdl_smb_bboard(hdl); 344 if (board_list == NULL) { 345 return (NULL); 346 } 347 348 if ((nvl = fm_nvlist_create(nva)) == NULL) /* freed by caller */ 349 return (NULL); 350 351 if ((snvl = fm_nvlist_create(nva)) == NULL) { 352 fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 353 return (NULL); 354 } 355 356 (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET, 357 unump->unum_offset); 358 359 if (unump->unum_chan == -1) { 360 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 361 board_list, 2, 362 "chip", cmi_hdl_smb_chipid(hdl), 363 "memory-controller", unump->unum_mc); 364 } else if (unump->unum_cs == -1) { 365 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 366 board_list, 3, 367 "chip", cmi_hdl_smb_chipid(hdl), 368 "memory-controller", unump->unum_mc, 369 "dram-channel", unump->unum_chan); 370 } else if (unump->unum_rank == -1) { 371 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 372 board_list, 4, 373 "chip", cmi_hdl_smb_chipid(hdl), 374 "memory-controller", unump->unum_mc, 375 "dram-channel", unump->unum_chan, 376 "dimm", unump->unum_cs); 377 } else { 378 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 379 board_list, 5, 380 "chip", cmi_hdl_smb_chipid(hdl), 381 "memory-controller", unump->unum_mc, 382 "dram-channel", unump->unum_chan, 383 "dimm", unump->unum_cs, 384 "rank", unump->unum_rank); 385 } 386 387 fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 388 389 return (nvl); 390 } 391 392 static nvlist_t * 393 gintel_ereport_create_resource_elem(nv_alloc_t *nva, mc_unum_t *unump) 394 { 395 nvlist_t *nvl, *snvl; 396 397 if ((nvl = fm_nvlist_create(nva)) == NULL) /* freed by caller */ 398 return (NULL); 399 400 if ((snvl = fm_nvlist_create(nva)) == NULL) { 401 fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 402 return (NULL); 403 } 404 405 (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET, 406 unump->unum_offset); 407 408 if (unump->unum_chan == -1) { 409 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 3, 410 "motherboard", unump->unum_board, 411 "chip", unump->unum_chip, 412 "memory-controller", unump->unum_mc); 413 } else if (unump->unum_cs == -1) { 414 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 4, 415 "motherboard", unump->unum_board, 416 "chip", unump->unum_chip, 417 "memory-controller", unump->unum_mc, 418 "dram-channel", unump->unum_chan); 419 } else if (unump->unum_rank == -1) { 420 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 5, 421 "motherboard", unump->unum_board, 422 "chip", unump->unum_chip, 423 "memory-controller", unump->unum_mc, 424 "dram-channel", unump->unum_chan, 425 "dimm", unump->unum_cs); 426 } else { 427 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 6, 428 "motherboard", unump->unum_board, 429 "chip", unump->unum_chip, 430 "memory-controller", unump->unum_mc, 431 "dram-channel", unump->unum_chan, 432 "dimm", unump->unum_cs, 433 "rank", unump->unum_rank); 434 } 435 436 fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 437 438 return (nvl); 439 } 440 441 static void 442 nehalem_ep_ereport_add_memory_error_counter(uint_t chipid, 443 uint32_t *this_err_counter_array) 444 { 445 int index; 446 447 for (index = 0; index < N_MC_COR_ECC_CNT; index ++) 448 this_err_counter_array[index] = MC_COR_ECC_CNT(chipid, index); 449 } 450 451 static int 452 gintel_cpu_generation(cmi_hdl_t hdl) 453 { 454 int cpu_generation = CPU_GENERATION_DONT_CARE; 455 456 if ((cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID) && 457 (cmi_hdl_model(hdl) == INTEL_NEHALEM_CPU_MODEL_ID)) 458 cpu_generation = CPU_GENERATION_NEHALEM_EP; 459 460 return (cpu_generation); 461 } 462 463 /*ARGSUSED*/ 464 void 465 gintel_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *ereport, 466 nv_alloc_t *nva, int banknum, uint64_t status, uint64_t addr, 467 uint64_t misc, void *mslogout, cms_cookie_t mscookie) 468 { 469 mc_unum_t unum; 470 nvlist_t *resource; 471 uint32_t synd = 0; 472 int chan = MCAX86_ERRCODE_CCCC(status); 473 uint8_t last_index, this_index; 474 int chipid; 475 476 if (chan == 0xf) 477 chan = -1; 478 479 if ((uintptr_t)mscookie & GINTEL_ERROR_MEM) { 480 unum.unum_board = 0; 481 unum.unum_chip = cmi_hdl_chipid(hdl); 482 unum.unum_mc = 0; 483 unum.unum_chan = chan; 484 unum.unum_cs = -1; 485 unum.unum_rank = -1; 486 unum.unum_offset = -1ULL; 487 if (status & MSR_MC_STATUS_MISCV) { 488 unum.unum_chan = 489 (misc & MSR_MC_MISC_MEM_CHANNEL_MASK) >> 490 MSR_MC_MISC_MEM_CHANNEL_SHIFT; 491 unum.unum_cs = 492 (misc & MSR_MC_MISC_MEM_DIMM_MASK) >> 493 MSR_MC_MISC_MEM_DIMM_SHIFT; 494 synd = (misc & MSR_MC_MISC_MEM_SYNDROME_MASK) >> 495 MSR_MC_MISC_MEM_SYNDROME_SHIFT; 496 fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ECC_SYND, 497 DATA_TYPE_UINT32, synd, 0); 498 } 499 if (status & MSR_MC_STATUS_ADDRV) { 500 fm_payload_set(ereport, FM_FMRI_MEM_PHYSADDR, 501 DATA_TYPE_UINT64, addr, NULL); 502 (void) cmi_mc_patounum(addr, 0, 0, synd, 0, &unum); 503 if (unum.unum_offset != -1ULL && 504 (unum.unum_offset & OFFSET_ROW_BANK_COL) != 0) { 505 fm_payload_set(ereport, 506 FM_EREPORT_PAYLOAD_NAME_BANK, 507 DATA_TYPE_INT32, 508 TCODE_OFFSET_BANK(unum.unum_offset), NULL); 509 fm_payload_set(ereport, 510 FM_EREPORT_PAYLOAD_NAME_CAS, 511 DATA_TYPE_INT32, 512 TCODE_OFFSET_CAS(unum.unum_offset), NULL); 513 fm_payload_set(ereport, 514 FM_EREPORT_PAYLOAD_NAME_RAS, 515 DATA_TYPE_INT32, 516 TCODE_OFFSET_RAS(unum.unum_offset), NULL); 517 } 518 } 519 520 if (!x86gentopo_legacy) { 521 resource = gintel_gentopo_ereport_create_resource_elem( 522 hdl, nva, &unum); 523 } else { 524 resource = gintel_ereport_create_resource_elem(nva, 525 &unum); 526 } 527 528 fm_payload_set(ereport, FM_EREPORT_PAYLOAD_NAME_RESOURCE, 529 DATA_TYPE_NVLIST_ARRAY, 1, &resource, NULL); 530 fm_nvlist_destroy(resource, nva ? FM_NVA_RETAIN:FM_NVA_FREE); 531 532 if (gintel_cpu_generation(hdl) == CPU_GENERATION_NEHALEM_EP) { 533 534 chipid = unum.unum_chip; 535 if (chipid < MAX_CPU_NODES) { 536 last_index = err_counter_index[chipid]; 537 this_index = 538 (last_index + 1) % ERR_COUNTER_INDEX; 539 err_counter_index[chipid] = this_index; 540 nehalem_ep_ereport_add_memory_error_counter( 541 chipid, 542 err_counter_array[chipid][this_index]); 543 fm_payload_set(ereport, 544 FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_THIS, 545 DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT, 546 err_counter_array[chipid][this_index], 547 NULL); 548 fm_payload_set(ereport, 549 FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_LAST, 550 DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT, 551 err_counter_array[chipid][last_index], 552 NULL); 553 } 554 } 555 } 556 } 557 558 boolean_t 559 gintel_bankctl_skipinit(cmi_hdl_t hdl, int banknum) 560 { 561 /* 562 * On Intel family 6 before QuickPath we must not enable machine check 563 * from bank 0 detectors. bank 0 is reserved for the platform 564 */ 565 566 if (banknum == 0 && 567 cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID && 568 cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID) 569 return (1); 570 else 571 return (0); 572 } 573 574 cms_api_ver_t _cms_api_version = CMS_API_VERSION_2; 575 576 const cms_ops_t _cms_ops = { 577 gintel_init, /* cms_init */ 578 NULL, /* cms_post_startup */ 579 NULL, /* cms_post_mpstartup */ 580 NULL, /* cms_logout_size */ 581 NULL, /* cms_mcgctl_val */ 582 gintel_bankctl_skipinit, /* cms_bankctl_skipinit */ 583 NULL, /* cms_bankctl_val */ 584 NULL, /* cms_bankstatus_skipinit */ 585 NULL, /* cms_bankstatus_val */ 586 NULL, /* cms_mca_init */ 587 NULL, /* cms_poll_ownermask */ 588 NULL, /* cms_bank_logout */ 589 gintel_error_action, /* cms_error_action */ 590 gintel_disp_match, /* cms_disp_match */ 591 gintel_ereport_class, /* cms_ereport_class */ 592 gintel_ereport_detector, /* cms_ereport_detector */ 593 NULL, /* cms_ereport_includestack */ 594 gintel_ereport_add_logout, /* cms_ereport_add_logout */ 595 NULL, /* cms_msrinject */ 596 NULL, /* cms_fini */ 597 }; 598 599 static struct modlcpu modlcpu = { 600 &mod_cpuops, 601 "Generic Intel model-specific MCA" 602 }; 603 604 static struct modlinkage modlinkage = { 605 MODREV_1, 606 { (void *)&modlcpu, NULL } 607 }; 608 609 int 610 _init(void) 611 { 612 return (mod_install(&modlinkage)); 613 } 614 615 int 616 _info(struct modinfo *modinfop) 617 { 618 return (mod_info(&modlinkage, modinfop)); 619 } 620 621 int 622 _fini(void) 623 { 624 return (mod_remove(&modlinkage)); 625 }