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