Home | History | Annotate | Download | only in genuineintel
      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