120c794b3Sgavinm /* 220c794b3Sgavinm * CDDL HEADER START 320c794b3Sgavinm * 420c794b3Sgavinm * The contents of this file are subject to the terms of the 520c794b3Sgavinm * Common Development and Distribution License (the "License"). 620c794b3Sgavinm * You may not use this file except in compliance with the License. 720c794b3Sgavinm * 820c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 920c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 1020c794b3Sgavinm * See the License for the specific language governing permissions 1120c794b3Sgavinm * and limitations under the License. 1220c794b3Sgavinm * 1320c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 1420c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1520c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 1620c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 1720c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 1820c794b3Sgavinm * 1920c794b3Sgavinm * CDDL HEADER END 2020c794b3Sgavinm */ 2120c794b3Sgavinm 2220c794b3Sgavinm /* 23c84b7bbeSAdrian Frost * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 2420c794b3Sgavinm */ 2520c794b3Sgavinm 2620c794b3Sgavinm /* 2720c794b3Sgavinm * Intel model-specific support. Right now all this conists of is 2820c794b3Sgavinm * to modify the ereport subclass to produce different ereport classes 2920c794b3Sgavinm * so that we can have different diagnosis rules and corresponding faults. 3020c794b3Sgavinm */ 3120c794b3Sgavinm 3220c794b3Sgavinm #include <sys/types.h> 3320c794b3Sgavinm #include <sys/cmn_err.h> 3420c794b3Sgavinm #include <sys/modctl.h> 3520c794b3Sgavinm #include <sys/mca_x86.h> 3620c794b3Sgavinm #include <sys/cpu_module_ms_impl.h> 3720c794b3Sgavinm #include <sys/mc_intel.h> 3820c794b3Sgavinm #include <sys/pci_cfgspace.h> 39e3d60c9bSAdrian Frost #include <sys/fm/protocol.h> 40074bb90dSTom Pothier #include <sys/fm/util.h> 41074bb90dSTom Pothier #include <sys/fm/smb/fmsmb.h> 42074bb90dSTom Pothier 43074bb90dSTom Pothier extern int x86gentopo_legacy; 4420c794b3Sgavinm 4520c794b3Sgavinm int gintel_ms_support_disable = 0; 4620c794b3Sgavinm int gintel_error_action_return = 0; 4720c794b3Sgavinm int gintel_ms_unconstrained = 0; 4820c794b3Sgavinm 49e3d60c9bSAdrian Frost int quickpath; 50e3d60c9bSAdrian Frost int max_bus_number = 0xff; 51e3d60c9bSAdrian Frost 52e3d60c9bSAdrian Frost #define ERR_COUNTER_INDEX 2 53e3d60c9bSAdrian Frost #define MAX_CPU_NODES 2 54e3d60c9bSAdrian Frost #define N_MC_COR_ECC_CNT 6 55e3d60c9bSAdrian Frost uint32_t err_counter_array[MAX_CPU_NODES][ERR_COUNTER_INDEX][N_MC_COR_ECC_CNT]; 56e3d60c9bSAdrian Frost uint8_t err_counter_index[MAX_CPU_NODES]; 57e3d60c9bSAdrian Frost 58e3d60c9bSAdrian Frost #define MAX_BUS_NUMBER max_bus_number 59e3d60c9bSAdrian Frost #define SOCKET_BUS(cpu) (MAX_BUS_NUMBER - (cpu)) 60e3d60c9bSAdrian Frost 61e3d60c9bSAdrian Frost #define MC_COR_ECC_CNT(chipid, reg) (*pci_getl_func)(SOCKET_BUS(chipid), \ 62e3d60c9bSAdrian Frost NEHALEM_EP_MEMORY_CONTROLLER_DEV, NEHALEM_EP_MEMORY_CONTROLLER_FUNC, \ 63e3d60c9bSAdrian Frost 0x80 + (reg) * 4) 64e3d60c9bSAdrian Frost 65e3d60c9bSAdrian Frost #define MSCOD_MEM_ECC_READ 0x1 66e3d60c9bSAdrian Frost #define MSCOD_MEM_ECC_SCRUB 0x2 67e3d60c9bSAdrian Frost #define MSCOD_MEM_WR_PARITY 0x4 68e3d60c9bSAdrian Frost #define MSCOD_MEM_REDUNDANT_MEM 0x8 69e3d60c9bSAdrian Frost #define MSCOD_MEM_SPARE_MEM 0x10 70e3d60c9bSAdrian Frost #define MSCOD_MEM_ILLEGAL_ADDR 0x20 71e3d60c9bSAdrian Frost #define MSCOD_MEM_BAD_ID 0x40 72e3d60c9bSAdrian Frost #define MSCOD_MEM_ADDR_PARITY 0x80 73e3d60c9bSAdrian Frost #define MSCOD_MEM_BYTE_PARITY 0x100 74e3d60c9bSAdrian Frost 75e3d60c9bSAdrian Frost #define GINTEL_ERROR_MEM 0x1000 76e3d60c9bSAdrian Frost #define GINTEL_ERROR_QUICKPATH 0x2000 77c84b7bbeSAdrian Frost #define GINTEL_ERROR_UNKNOWN 0x4000 78e3d60c9bSAdrian Frost 79e3d60c9bSAdrian Frost #define GINTEL_ERR_SPARE_MEM (GINTEL_ERROR_MEM | 1) 80e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_UE (GINTEL_ERROR_MEM | 2) 81e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_CE (GINTEL_ERROR_MEM | 3) 82e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_PARITY (GINTEL_ERROR_MEM | 4) 83e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_ADDR_PARITY (GINTEL_ERROR_MEM | 5) 84e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_REDUNDANT (GINTEL_ERROR_MEM | 6) 85e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_BAD_ADDR (GINTEL_ERROR_MEM | 7) 86e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_BAD_ID (GINTEL_ERROR_MEM | 8) 87e3d60c9bSAdrian Frost #define GINTEL_ERR_MEM_UNKNOWN (GINTEL_ERROR_MEM | 0xfff) 88e3d60c9bSAdrian Frost 89e3d60c9bSAdrian Frost #define MSR_MC_MISC_MEM_CHANNEL_MASK 0x00000000000c0000ULL 90e3d60c9bSAdrian Frost #define MSR_MC_MISC_MEM_CHANNEL_SHIFT 18 91e3d60c9bSAdrian Frost #define MSR_MC_MISC_MEM_DIMM_MASK 0x0000000000030000ULL 92e3d60c9bSAdrian Frost #define MSR_MC_MISC_MEM_DIMM_SHIFT 16 93e3d60c9bSAdrian Frost #define MSR_MC_MISC_MEM_SYNDROME_MASK 0xffffffff00000000ULL 94e3d60c9bSAdrian Frost #define MSR_MC_MISC_MEM_SYNDROME_SHIFT 32 95e3d60c9bSAdrian Frost 96e3d60c9bSAdrian Frost #define CPU_GENERATION_DONT_CARE 0 97e3d60c9bSAdrian Frost #define CPU_GENERATION_NEHALEM_EP 1 98e3d60c9bSAdrian Frost 99c84b7bbeSAdrian Frost #define INTEL_CPU_6_ID 0x6 100e3d60c9bSAdrian Frost #define INTEL_NEHALEM_CPU_FAMILY_ID 0x6 101e3d60c9bSAdrian Frost #define INTEL_NEHALEM_CPU_MODEL_ID 0x1A 102e3d60c9bSAdrian Frost 103e3d60c9bSAdrian Frost #define NEHALEM_EP_MEMORY_CONTROLLER_DEV 0x3 104e3d60c9bSAdrian Frost #define NEHALEM_EP_MEMORY_CONTROLLER_FUNC 0x2 105e3d60c9bSAdrian Frost 10620c794b3Sgavinm /*ARGSUSED*/ 10720c794b3Sgavinm int 10820c794b3Sgavinm gintel_init(cmi_hdl_t hdl, void **datap) 10920c794b3Sgavinm { 11020c794b3Sgavinm uint32_t nb_chipset; 11120c794b3Sgavinm 11220c794b3Sgavinm if (gintel_ms_support_disable) 11320c794b3Sgavinm return (ENOTSUP); 11420c794b3Sgavinm 115*7417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_MCA)) 11620c794b3Sgavinm return (ENOTSUP); 11720c794b3Sgavinm 11820c794b3Sgavinm nb_chipset = (*pci_getl_func)(0, 0, 0, 0x0); 11920c794b3Sgavinm switch (nb_chipset) { 12020c794b3Sgavinm case INTEL_NB_7300: 12120c794b3Sgavinm case INTEL_NB_5000P: 12220c794b3Sgavinm case INTEL_NB_5000X: 12320c794b3Sgavinm case INTEL_NB_5000V: 12420c794b3Sgavinm case INTEL_NB_5000Z: 1255f28a827Saf case INTEL_NB_5400: 1265f28a827Saf case INTEL_NB_5400A: 1275f28a827Saf case INTEL_NB_5400B: 12820c794b3Sgavinm if (!gintel_ms_unconstrained) 12920c794b3Sgavinm gintel_error_action_return |= CMS_ERRSCOPE_POISONED; 13020c794b3Sgavinm break; 131e3d60c9bSAdrian Frost case INTEL_QP_IO: 132ee9ef9e5SAdrian Frost case INTEL_QP_WP: 133e3d60c9bSAdrian Frost case INTEL_QP_36D: 134e3d60c9bSAdrian Frost case INTEL_QP_24D: 135ee9ef9e5SAdrian Frost case INTEL_QP_U1: 136ee9ef9e5SAdrian Frost case INTEL_QP_U2: 137ee9ef9e5SAdrian Frost case INTEL_QP_U3: 138ee9ef9e5SAdrian Frost case INTEL_QP_U4: 13935366b93SAdrian Frost case INTEL_QP_JF: 14035366b93SAdrian Frost case INTEL_QP_JF0: 14135366b93SAdrian Frost case INTEL_QP_JF1: 14235366b93SAdrian Frost case INTEL_QP_JF2: 14335366b93SAdrian Frost case INTEL_QP_JF3: 14435366b93SAdrian Frost case INTEL_QP_JF4: 14535366b93SAdrian Frost case INTEL_QP_JF5: 14635366b93SAdrian Frost case INTEL_QP_JF6: 14735366b93SAdrian Frost case INTEL_QP_JF7: 14835366b93SAdrian Frost case INTEL_QP_JF8: 14935366b93SAdrian Frost case INTEL_QP_JF9: 15035366b93SAdrian Frost case INTEL_QP_JFa: 15135366b93SAdrian Frost case INTEL_QP_JFb: 15235366b93SAdrian Frost case INTEL_QP_JFc: 15335366b93SAdrian Frost case INTEL_QP_JFd: 15435366b93SAdrian Frost case INTEL_QP_JFe: 15535366b93SAdrian Frost case INTEL_QP_JFf: 156e3d60c9bSAdrian Frost quickpath = 1; 157e3d60c9bSAdrian Frost break; 15820c794b3Sgavinm default: 15920c794b3Sgavinm break; 16020c794b3Sgavinm } 16120c794b3Sgavinm return (0); 16220c794b3Sgavinm } 16320c794b3Sgavinm 16420c794b3Sgavinm /*ARGSUSED*/ 16520c794b3Sgavinm uint32_t 16620c794b3Sgavinm gintel_error_action(cmi_hdl_t hdl, int ismc, int bank, 16720c794b3Sgavinm uint64_t status, uint64_t addr, uint64_t misc, void *mslogout) 16820c794b3Sgavinm { 169c84b7bbeSAdrian Frost uint32_t rc; 170c84b7bbeSAdrian Frost 171c84b7bbeSAdrian Frost if (ismc == 0 && bank == 0 && 172c84b7bbeSAdrian Frost cmi_hdl_family(hdl) == INTEL_CPU_6_ID && 173c84b7bbeSAdrian Frost cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID && 174c84b7bbeSAdrian Frost MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && 175c84b7bbeSAdrian Frost MCAX86_MSERRCODE(status) == 0) { 176c84b7bbeSAdrian Frost rc = CMS_ERRSCOPE_CURCONTEXT_OK | CMS_ERRSCOPE_CLEARED_UC; 177c84b7bbeSAdrian Frost } else if ((status & MSR_MC_STATUS_PCC) == 0) { 178c84b7bbeSAdrian Frost rc = gintel_error_action_return; 179c84b7bbeSAdrian Frost } else { 180c84b7bbeSAdrian Frost rc = gintel_error_action_return & ~CMS_ERRSCOPE_POISONED; 181c84b7bbeSAdrian Frost } 182c84b7bbeSAdrian Frost return (rc); 18320c794b3Sgavinm } 18420c794b3Sgavinm 18520c794b3Sgavinm /*ARGSUSED*/ 186e3d60c9bSAdrian Frost cms_cookie_t 187c84b7bbeSAdrian Frost gintel_disp_match(cmi_hdl_t hdl, int ismc, int bank, uint64_t status, 188e3d60c9bSAdrian Frost uint64_t addr, uint64_t misc, void *mslogout) 189e3d60c9bSAdrian Frost { 190e3d60c9bSAdrian Frost cms_cookie_t rt = (cms_cookie_t)NULL; 191e3d60c9bSAdrian Frost uint16_t mcacode = MCAX86_ERRCODE(status); 192e3d60c9bSAdrian Frost uint16_t mscode = MCAX86_MSERRCODE(status); 193e3d60c9bSAdrian Frost 194e3d60c9bSAdrian Frost if (MCAX86_ERRCODE_ISMEMORY_CONTROLLER(mcacode)) { 195e3d60c9bSAdrian Frost /* 196e3d60c9bSAdrian Frost * memory controller errors 197e3d60c9bSAdrian Frost */ 198e3d60c9bSAdrian Frost if (mscode & MSCOD_MEM_SPARE_MEM) { 199e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_SPARE_MEM; 200e3d60c9bSAdrian Frost } else if (mscode & (MSCOD_MEM_ECC_READ | 201e3d60c9bSAdrian Frost MSCOD_MEM_ECC_SCRUB)) { 202e3d60c9bSAdrian Frost if (status & MSR_MC_STATUS_UC) 203e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_UE; 204e3d60c9bSAdrian Frost else 205e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_CE; 206e3d60c9bSAdrian Frost } else if (mscode & (MSCOD_MEM_WR_PARITY | 207e3d60c9bSAdrian Frost MSCOD_MEM_BYTE_PARITY)) { 208e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_PARITY; 209e3d60c9bSAdrian Frost } else if (mscode & MSCOD_MEM_ADDR_PARITY) { 210e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_ADDR_PARITY; 211e3d60c9bSAdrian Frost } else if (mscode & MSCOD_MEM_REDUNDANT_MEM) { 212e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_REDUNDANT; 213e3d60c9bSAdrian Frost } else if (mscode & MSCOD_MEM_ILLEGAL_ADDR) { 214e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ADDR; 215e3d60c9bSAdrian Frost } else if (mscode & MSCOD_MEM_BAD_ID) { 216e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ID; 217e3d60c9bSAdrian Frost } else { 218e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERR_MEM_UNKNOWN; 219e3d60c9bSAdrian Frost } 220e3d60c9bSAdrian Frost } else if (quickpath && 221e3d60c9bSAdrian Frost MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status))) { 222e3d60c9bSAdrian Frost rt = (cms_cookie_t)GINTEL_ERROR_QUICKPATH; 223c84b7bbeSAdrian Frost } else if (ismc == 0 && bank == 0 && 224c84b7bbeSAdrian Frost cmi_hdl_family(hdl) == INTEL_CPU_6_ID && 225c84b7bbeSAdrian Frost cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID && 226c84b7bbeSAdrian Frost MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && 227c84b7bbeSAdrian Frost MCAX86_MSERRCODE(status) == 0) { 228c84b7bbeSAdrian Frost rt = (cms_cookie_t)GINTEL_ERROR_UNKNOWN; 229e3d60c9bSAdrian Frost } 230e3d60c9bSAdrian Frost return (rt); 231e3d60c9bSAdrian Frost } 232e3d60c9bSAdrian Frost 233e3d60c9bSAdrian Frost /*ARGSUSED*/ 23420c794b3Sgavinm void 23520c794b3Sgavinm gintel_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie, 23620c794b3Sgavinm const char **cpuclsp, const char **leafclsp) 23720c794b3Sgavinm { 23820c794b3Sgavinm *cpuclsp = FM_EREPORT_CPU_INTEL; 239e3d60c9bSAdrian Frost switch ((uintptr_t)mscookie) { 240e3d60c9bSAdrian Frost case GINTEL_ERROR_QUICKPATH: 241e3d60c9bSAdrian Frost *leafclsp = "quickpath.interconnect"; 242e3d60c9bSAdrian Frost break; 243e3d60c9bSAdrian Frost case GINTEL_ERR_SPARE_MEM: 244e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_spare"; 245e3d60c9bSAdrian Frost break; 246e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_UE: 247e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_ue"; 248e3d60c9bSAdrian Frost break; 249e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_CE: 250e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_ce"; 251e3d60c9bSAdrian Frost break; 252e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_PARITY: 253e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_parity"; 254e3d60c9bSAdrian Frost break; 255e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_ADDR_PARITY: 256e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_addr_parity"; 257e3d60c9bSAdrian Frost break; 258e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_REDUNDANT: 259e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_redundant"; 260e3d60c9bSAdrian Frost break; 261e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_BAD_ADDR: 262e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_bad_addr"; 263e3d60c9bSAdrian Frost break; 264e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_BAD_ID: 265e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_bad_id"; 266e3d60c9bSAdrian Frost break; 267e3d60c9bSAdrian Frost case GINTEL_ERR_MEM_UNKNOWN: 268e3d60c9bSAdrian Frost *leafclsp = "quickpath.mem_unknown"; 269e3d60c9bSAdrian Frost break; 270c84b7bbeSAdrian Frost case GINTEL_ERROR_UNKNOWN: 271c84b7bbeSAdrian Frost *leafclsp = "unknown"; 272c84b7bbeSAdrian Frost break; 273e3d60c9bSAdrian Frost } 274e3d60c9bSAdrian Frost } 275e3d60c9bSAdrian Frost 276074bb90dSTom Pothier static nvlist_t * 277074bb90dSTom Pothier gintel_gentopo_ereport_detector(cmi_hdl_t hdl, cms_cookie_t mscookie, 278074bb90dSTom Pothier nv_alloc_t *nva) 279074bb90dSTom Pothier { 280074bb90dSTom Pothier nvlist_t *nvl = (nvlist_t *)NULL; 281074bb90dSTom Pothier nvlist_t *board_list = (nvlist_t *)NULL; 282074bb90dSTom Pothier 283074bb90dSTom Pothier if (mscookie) { 284074bb90dSTom Pothier board_list = cmi_hdl_smb_bboard(hdl); 285074bb90dSTom Pothier 286074bb90dSTom Pothier if (board_list == NULL) 287074bb90dSTom Pothier return (NULL); 288074bb90dSTom Pothier 289074bb90dSTom Pothier if ((nvl = fm_nvlist_create(nva)) == NULL) 290074bb90dSTom Pothier return (NULL); 291074bb90dSTom Pothier 292074bb90dSTom Pothier if ((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) { 293074bb90dSTom Pothier fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, 294074bb90dSTom Pothier NULL, NULL, board_list, 1, 295074bb90dSTom Pothier "chip", cmi_hdl_smb_chipid(hdl)); 296074bb90dSTom Pothier } else { 297074bb90dSTom Pothier fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, 298074bb90dSTom Pothier NULL, NULL, board_list, 2, 299074bb90dSTom Pothier "chip", cmi_hdl_smb_chipid(hdl), 300074bb90dSTom Pothier "memory-controller", 0); 301074bb90dSTom Pothier } 302074bb90dSTom Pothier } 303074bb90dSTom Pothier return (nvl); 304074bb90dSTom Pothier } 305074bb90dSTom Pothier 306491f61a1SYanmin Sun /*ARGSUSED*/ 307e3d60c9bSAdrian Frost nvlist_t * 308491f61a1SYanmin Sun gintel_ereport_detector(cmi_hdl_t hdl, int bankno, cms_cookie_t mscookie, 309491f61a1SYanmin Sun nv_alloc_t *nva) 310e3d60c9bSAdrian Frost { 311e3d60c9bSAdrian Frost nvlist_t *nvl = (nvlist_t *)NULL; 312e3d60c9bSAdrian Frost 313074bb90dSTom Pothier if (!x86gentopo_legacy) { 314074bb90dSTom Pothier nvl = gintel_gentopo_ereport_detector(hdl, mscookie, nva); 315074bb90dSTom Pothier return (nvl); 316074bb90dSTom Pothier } 317074bb90dSTom Pothier 318e3d60c9bSAdrian Frost if (mscookie) { 319e3d60c9bSAdrian Frost if ((nvl = fm_nvlist_create(nva)) == NULL) 320e3d60c9bSAdrian Frost return (NULL); 321c84b7bbeSAdrian Frost if (((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) || 322c84b7bbeSAdrian Frost ((uintptr_t)mscookie & GINTEL_ERROR_UNKNOWN)) { 323e3d60c9bSAdrian Frost fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 2, 324e3d60c9bSAdrian Frost "motherboard", 0, 325e3d60c9bSAdrian Frost "chip", cmi_hdl_chipid(hdl)); 326e3d60c9bSAdrian Frost } else { 327e3d60c9bSAdrian Frost fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3, 328e3d60c9bSAdrian Frost "motherboard", 0, 329e3d60c9bSAdrian Frost "chip", cmi_hdl_chipid(hdl), 330e3d60c9bSAdrian Frost "memory-controller", 0); 331e3d60c9bSAdrian Frost } 332e3d60c9bSAdrian Frost } 333e3d60c9bSAdrian Frost return (nvl); 334e3d60c9bSAdrian Frost } 335e3d60c9bSAdrian Frost 336e3d60c9bSAdrian Frost static nvlist_t * 337074bb90dSTom Pothier gintel_gentopo_ereport_create_resource_elem(cmi_hdl_t hdl, nv_alloc_t *nva, 338074bb90dSTom Pothier mc_unum_t *unump) 339074bb90dSTom Pothier { 340074bb90dSTom Pothier nvlist_t *nvl, *snvl; 341074bb90dSTom Pothier nvlist_t *board_list = NULL; 342074bb90dSTom Pothier 343074bb90dSTom Pothier board_list = cmi_hdl_smb_bboard(hdl); 344074bb90dSTom Pothier if (board_list == NULL) { 345074bb90dSTom Pothier return (NULL); 346074bb90dSTom Pothier } 347074bb90dSTom Pothier 348074bb90dSTom Pothier if ((nvl = fm_nvlist_create(nva)) == NULL) /* freed by caller */ 349074bb90dSTom Pothier return (NULL); 350074bb90dSTom Pothier 351074bb90dSTom Pothier if ((snvl = fm_nvlist_create(nva)) == NULL) { 352074bb90dSTom Pothier fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 353074bb90dSTom Pothier return (NULL); 354074bb90dSTom Pothier } 355074bb90dSTom Pothier 356074bb90dSTom Pothier (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET, 357074bb90dSTom Pothier unump->unum_offset); 358074bb90dSTom Pothier 359074bb90dSTom Pothier if (unump->unum_chan == -1) { 360074bb90dSTom Pothier fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 361074bb90dSTom Pothier board_list, 2, 362074bb90dSTom Pothier "chip", cmi_hdl_smb_chipid(hdl), 363074bb90dSTom Pothier "memory-controller", unump->unum_mc); 364074bb90dSTom Pothier } else if (unump->unum_cs == -1) { 365074bb90dSTom Pothier fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 366074bb90dSTom Pothier board_list, 3, 367074bb90dSTom Pothier "chip", cmi_hdl_smb_chipid(hdl), 368074bb90dSTom Pothier "memory-controller", unump->unum_mc, 369074bb90dSTom Pothier "dram-channel", unump->unum_chan); 370074bb90dSTom Pothier } else if (unump->unum_rank == -1) { 371074bb90dSTom Pothier fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 372074bb90dSTom Pothier board_list, 4, 373074bb90dSTom Pothier "chip", cmi_hdl_smb_chipid(hdl), 374074bb90dSTom Pothier "memory-controller", unump->unum_mc, 375074bb90dSTom Pothier "dram-channel", unump->unum_chan, 376074bb90dSTom Pothier "dimm", unump->unum_cs); 377074bb90dSTom Pothier } else { 378074bb90dSTom Pothier fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 379074bb90dSTom Pothier board_list, 5, 380074bb90dSTom Pothier "chip", cmi_hdl_smb_chipid(hdl), 381074bb90dSTom Pothier "memory-controller", unump->unum_mc, 382074bb90dSTom Pothier "dram-channel", unump->unum_chan, 383074bb90dSTom Pothier "dimm", unump->unum_cs, 384074bb90dSTom Pothier "rank", unump->unum_rank); 385074bb90dSTom Pothier } 386074bb90dSTom Pothier 387074bb90dSTom Pothier fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 388074bb90dSTom Pothier 389074bb90dSTom Pothier return (nvl); 390074bb90dSTom Pothier } 391074bb90dSTom Pothier 392074bb90dSTom Pothier static nvlist_t * 393e3d60c9bSAdrian Frost gintel_ereport_create_resource_elem(nv_alloc_t *nva, mc_unum_t *unump) 394e3d60c9bSAdrian Frost { 395e3d60c9bSAdrian Frost nvlist_t *nvl, *snvl; 396e3d60c9bSAdrian Frost 397e3d60c9bSAdrian Frost if ((nvl = fm_nvlist_create(nva)) == NULL) /* freed by caller */ 398e3d60c9bSAdrian Frost return (NULL); 399e3d60c9bSAdrian Frost 400e3d60c9bSAdrian Frost if ((snvl = fm_nvlist_create(nva)) == NULL) { 401e3d60c9bSAdrian Frost fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 402e3d60c9bSAdrian Frost return (NULL); 403e3d60c9bSAdrian Frost } 404e3d60c9bSAdrian Frost 405e3d60c9bSAdrian Frost (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET, 406e3d60c9bSAdrian Frost unump->unum_offset); 407e3d60c9bSAdrian Frost 408e3d60c9bSAdrian Frost if (unump->unum_chan == -1) { 409e3d60c9bSAdrian Frost fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 3, 410e3d60c9bSAdrian Frost "motherboard", unump->unum_board, 411e3d60c9bSAdrian Frost "chip", unump->unum_chip, 412e3d60c9bSAdrian Frost "memory-controller", unump->unum_mc); 413e3d60c9bSAdrian Frost } else if (unump->unum_cs == -1) { 414e3d60c9bSAdrian Frost fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 4, 415e3d60c9bSAdrian Frost "motherboard", unump->unum_board, 416e3d60c9bSAdrian Frost "chip", unump->unum_chip, 417e3d60c9bSAdrian Frost "memory-controller", unump->unum_mc, 418e3d60c9bSAdrian Frost "dram-channel", unump->unum_chan); 419e3d60c9bSAdrian Frost } else if (unump->unum_rank == -1) { 420e3d60c9bSAdrian Frost fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 5, 421e3d60c9bSAdrian Frost "motherboard", unump->unum_board, 422e3d60c9bSAdrian Frost "chip", unump->unum_chip, 423e3d60c9bSAdrian Frost "memory-controller", unump->unum_mc, 424e3d60c9bSAdrian Frost "dram-channel", unump->unum_chan, 425e3d60c9bSAdrian Frost "dimm", unump->unum_cs); 426e3d60c9bSAdrian Frost } else { 427e3d60c9bSAdrian Frost fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 6, 428e3d60c9bSAdrian Frost "motherboard", unump->unum_board, 429e3d60c9bSAdrian Frost "chip", unump->unum_chip, 430e3d60c9bSAdrian Frost "memory-controller", unump->unum_mc, 431e3d60c9bSAdrian Frost "dram-channel", unump->unum_chan, 432e3d60c9bSAdrian Frost "dimm", unump->unum_cs, 433e3d60c9bSAdrian Frost "rank", unump->unum_rank); 434e3d60c9bSAdrian Frost } 435e3d60c9bSAdrian Frost 436e3d60c9bSAdrian Frost fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE); 437e3d60c9bSAdrian Frost 438e3d60c9bSAdrian Frost return (nvl); 439e3d60c9bSAdrian Frost } 440e3d60c9bSAdrian Frost 441e3d60c9bSAdrian Frost static void 442e3d60c9bSAdrian Frost nehalem_ep_ereport_add_memory_error_counter(uint_t chipid, 443e3d60c9bSAdrian Frost uint32_t *this_err_counter_array) 444e3d60c9bSAdrian Frost { 445e3d60c9bSAdrian Frost int index; 446e3d60c9bSAdrian Frost 447e3d60c9bSAdrian Frost for (index = 0; index < N_MC_COR_ECC_CNT; index ++) 448e3d60c9bSAdrian Frost this_err_counter_array[index] = MC_COR_ECC_CNT(chipid, index); 449e3d60c9bSAdrian Frost } 450e3d60c9bSAdrian Frost 451e3d60c9bSAdrian Frost static int 452728f047cSAdrian Frost gintel_cpu_generation(cmi_hdl_t hdl) 453e3d60c9bSAdrian Frost { 454e3d60c9bSAdrian Frost int cpu_generation = CPU_GENERATION_DONT_CARE; 455e3d60c9bSAdrian Frost 456728f047cSAdrian Frost if ((cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID) && 457728f047cSAdrian Frost (cmi_hdl_model(hdl) == INTEL_NEHALEM_CPU_MODEL_ID)) 458e3d60c9bSAdrian Frost cpu_generation = CPU_GENERATION_NEHALEM_EP; 459e3d60c9bSAdrian Frost 460e3d60c9bSAdrian Frost return (cpu_generation); 461e3d60c9bSAdrian Frost } 462e3d60c9bSAdrian Frost 463e3d60c9bSAdrian Frost /*ARGSUSED*/ 464e3d60c9bSAdrian Frost void 465e3d60c9bSAdrian Frost gintel_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *ereport, 466e3d60c9bSAdrian Frost nv_alloc_t *nva, int banknum, uint64_t status, uint64_t addr, 467e3d60c9bSAdrian Frost uint64_t misc, void *mslogout, cms_cookie_t mscookie) 468e3d60c9bSAdrian Frost { 469e3d60c9bSAdrian Frost mc_unum_t unum; 470e3d60c9bSAdrian Frost nvlist_t *resource; 471e3d60c9bSAdrian Frost uint32_t synd = 0; 472e3d60c9bSAdrian Frost int chan = MCAX86_ERRCODE_CCCC(status); 473e3d60c9bSAdrian Frost uint8_t last_index, this_index; 474e3d60c9bSAdrian Frost int chipid; 475e3d60c9bSAdrian Frost 476e3d60c9bSAdrian Frost if (chan == 0xf) 477e3d60c9bSAdrian Frost chan = -1; 478e3d60c9bSAdrian Frost 479e3d60c9bSAdrian Frost if ((uintptr_t)mscookie & GINTEL_ERROR_MEM) { 480e3d60c9bSAdrian Frost unum.unum_board = 0; 481e3d60c9bSAdrian Frost unum.unum_chip = cmi_hdl_chipid(hdl); 482e3d60c9bSAdrian Frost unum.unum_mc = 0; 483e3d60c9bSAdrian Frost unum.unum_chan = chan; 484e3d60c9bSAdrian Frost unum.unum_cs = -1; 485e3d60c9bSAdrian Frost unum.unum_rank = -1; 486e3d60c9bSAdrian Frost unum.unum_offset = -1ULL; 487e3d60c9bSAdrian Frost if (status & MSR_MC_STATUS_MISCV) { 488e3d60c9bSAdrian Frost unum.unum_chan = 489e3d60c9bSAdrian Frost (misc & MSR_MC_MISC_MEM_CHANNEL_MASK) >> 490e3d60c9bSAdrian Frost MSR_MC_MISC_MEM_CHANNEL_SHIFT; 491e3d60c9bSAdrian Frost unum.unum_cs = 492e3d60c9bSAdrian Frost (misc & MSR_MC_MISC_MEM_DIMM_MASK) >> 493e3d60c9bSAdrian Frost MSR_MC_MISC_MEM_DIMM_SHIFT; 494e3d60c9bSAdrian Frost synd = (misc & MSR_MC_MISC_MEM_SYNDROME_MASK) >> 495e3d60c9bSAdrian Frost MSR_MC_MISC_MEM_SYNDROME_SHIFT; 496e3d60c9bSAdrian Frost fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ECC_SYND, 497e3d60c9bSAdrian Frost DATA_TYPE_UINT32, synd, 0); 498e3d60c9bSAdrian Frost } 499e3d60c9bSAdrian Frost if (status & MSR_MC_STATUS_ADDRV) { 500e3d60c9bSAdrian Frost fm_payload_set(ereport, FM_FMRI_MEM_PHYSADDR, 501e3d60c9bSAdrian Frost DATA_TYPE_UINT64, addr, NULL); 502e3d60c9bSAdrian Frost (void) cmi_mc_patounum(addr, 0, 0, synd, 0, &unum); 503f899e573SVuong Nguyen if (unum.unum_offset != -1ULL && 504f899e573SVuong Nguyen (unum.unum_offset & OFFSET_ROW_BANK_COL) != 0) { 505f899e573SVuong Nguyen fm_payload_set(ereport, 506f899e573SVuong Nguyen FM_EREPORT_PAYLOAD_NAME_BANK, 507f899e573SVuong Nguyen DATA_TYPE_INT32, 508f899e573SVuong Nguyen TCODE_OFFSET_BANK(unum.unum_offset), NULL); 509f899e573SVuong Nguyen fm_payload_set(ereport, 510f899e573SVuong Nguyen FM_EREPORT_PAYLOAD_NAME_CAS, 511f899e573SVuong Nguyen DATA_TYPE_INT32, 512f899e573SVuong Nguyen TCODE_OFFSET_CAS(unum.unum_offset), NULL); 513f899e573SVuong Nguyen fm_payload_set(ereport, 514f899e573SVuong Nguyen FM_EREPORT_PAYLOAD_NAME_RAS, 515f899e573SVuong Nguyen DATA_TYPE_INT32, 516f899e573SVuong Nguyen TCODE_OFFSET_RAS(unum.unum_offset), NULL); 517f899e573SVuong Nguyen } 518e3d60c9bSAdrian Frost } 519074bb90dSTom Pothier 520074bb90dSTom Pothier if (!x86gentopo_legacy) { 521074bb90dSTom Pothier resource = gintel_gentopo_ereport_create_resource_elem( 522074bb90dSTom Pothier hdl, nva, &unum); 523074bb90dSTom Pothier } else { 524074bb90dSTom Pothier resource = gintel_ereport_create_resource_elem(nva, 525074bb90dSTom Pothier &unum); 526074bb90dSTom Pothier } 527074bb90dSTom Pothier 528e3d60c9bSAdrian Frost fm_payload_set(ereport, FM_EREPORT_PAYLOAD_NAME_RESOURCE, 529e3d60c9bSAdrian Frost DATA_TYPE_NVLIST_ARRAY, 1, &resource, NULL); 530e3d60c9bSAdrian Frost fm_nvlist_destroy(resource, nva ? FM_NVA_RETAIN:FM_NVA_FREE); 531e3d60c9bSAdrian Frost 532728f047cSAdrian Frost if (gintel_cpu_generation(hdl) == CPU_GENERATION_NEHALEM_EP) { 533e3d60c9bSAdrian Frost 534728f047cSAdrian Frost chipid = unum.unum_chip; 535e3d60c9bSAdrian Frost if (chipid < MAX_CPU_NODES) { 536e3d60c9bSAdrian Frost last_index = err_counter_index[chipid]; 537e3d60c9bSAdrian Frost this_index = 538e3d60c9bSAdrian Frost (last_index + 1) % ERR_COUNTER_INDEX; 539e3d60c9bSAdrian Frost err_counter_index[chipid] = this_index; 540e3d60c9bSAdrian Frost nehalem_ep_ereport_add_memory_error_counter( 541e3d60c9bSAdrian Frost chipid, 542e3d60c9bSAdrian Frost err_counter_array[chipid][this_index]); 543e3d60c9bSAdrian Frost fm_payload_set(ereport, 544e3d60c9bSAdrian Frost FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_THIS, 545e3d60c9bSAdrian Frost DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT, 546e3d60c9bSAdrian Frost err_counter_array[chipid][this_index], 547e3d60c9bSAdrian Frost NULL); 548e3d60c9bSAdrian Frost fm_payload_set(ereport, 549e3d60c9bSAdrian Frost FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_LAST, 550e3d60c9bSAdrian Frost DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT, 551e3d60c9bSAdrian Frost err_counter_array[chipid][last_index], 552e3d60c9bSAdrian Frost NULL); 553e3d60c9bSAdrian Frost } 554e3d60c9bSAdrian Frost } 555e3d60c9bSAdrian Frost } 556e3d60c9bSAdrian Frost } 557e3d60c9bSAdrian Frost 558e3d60c9bSAdrian Frost boolean_t 559e3d60c9bSAdrian Frost gintel_bankctl_skipinit(cmi_hdl_t hdl, int banknum) 560e3d60c9bSAdrian Frost { 561e3d60c9bSAdrian Frost /* 562e3d60c9bSAdrian Frost * On Intel family 6 before QuickPath we must not enable machine check 563e3d60c9bSAdrian Frost * from bank 0 detectors. bank 0 is reserved for the platform 564e3d60c9bSAdrian Frost */ 565e3d60c9bSAdrian Frost 566e3d60c9bSAdrian Frost if (banknum == 0 && 567e3d60c9bSAdrian Frost cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID && 568e3d60c9bSAdrian Frost cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID) 569e3d60c9bSAdrian Frost return (1); 570e3d60c9bSAdrian Frost else 571e3d60c9bSAdrian Frost return (0); 57220c794b3Sgavinm } 57320c794b3Sgavinm 574c84b7bbeSAdrian Frost cms_api_ver_t _cms_api_version = CMS_API_VERSION_2; 57520c794b3Sgavinm 57620c794b3Sgavinm const cms_ops_t _cms_ops = { 57720c794b3Sgavinm gintel_init, /* cms_init */ 57820c794b3Sgavinm NULL, /* cms_post_startup */ 57920c794b3Sgavinm NULL, /* cms_post_mpstartup */ 58020c794b3Sgavinm NULL, /* cms_logout_size */ 58120c794b3Sgavinm NULL, /* cms_mcgctl_val */ 582e3d60c9bSAdrian Frost gintel_bankctl_skipinit, /* cms_bankctl_skipinit */ 58320c794b3Sgavinm NULL, /* cms_bankctl_val */ 58420c794b3Sgavinm NULL, /* cms_bankstatus_skipinit */ 58520c794b3Sgavinm NULL, /* cms_bankstatus_val */ 58620c794b3Sgavinm NULL, /* cms_mca_init */ 58720c794b3Sgavinm NULL, /* cms_poll_ownermask */ 58820c794b3Sgavinm NULL, /* cms_bank_logout */ 58920c794b3Sgavinm gintel_error_action, /* cms_error_action */ 590e3d60c9bSAdrian Frost gintel_disp_match, /* cms_disp_match */ 59120c794b3Sgavinm gintel_ereport_class, /* cms_ereport_class */ 592e3d60c9bSAdrian Frost gintel_ereport_detector, /* cms_ereport_detector */ 59320c794b3Sgavinm NULL, /* cms_ereport_includestack */ 594e3d60c9bSAdrian Frost gintel_ereport_add_logout, /* cms_ereport_add_logout */ 59520c794b3Sgavinm NULL, /* cms_msrinject */ 59620c794b3Sgavinm NULL, /* cms_fini */ 59720c794b3Sgavinm }; 59820c794b3Sgavinm 59920c794b3Sgavinm static struct modlcpu modlcpu = { 60020c794b3Sgavinm &mod_cpuops, 60120c794b3Sgavinm "Generic Intel model-specific MCA" 60220c794b3Sgavinm }; 60320c794b3Sgavinm 60420c794b3Sgavinm static struct modlinkage modlinkage = { 60520c794b3Sgavinm MODREV_1, 60620c794b3Sgavinm (void *)&modlcpu, 60720c794b3Sgavinm NULL 60820c794b3Sgavinm }; 60920c794b3Sgavinm 61020c794b3Sgavinm int 61120c794b3Sgavinm _init(void) 61220c794b3Sgavinm { 61320c794b3Sgavinm return (mod_install(&modlinkage)); 61420c794b3Sgavinm } 61520c794b3Sgavinm 61620c794b3Sgavinm int 61720c794b3Sgavinm _info(struct modinfo *modinfop) 61820c794b3Sgavinm { 61920c794b3Sgavinm return (mod_info(&modlinkage, modinfop)); 62020c794b3Sgavinm } 62120c794b3Sgavinm 62220c794b3Sgavinm int 62320c794b3Sgavinm _fini(void) 62420c794b3Sgavinm { 62520c794b3Sgavinm return (mod_remove(&modlinkage)); 62620c794b3Sgavinm } 627