xref: /titanic_52/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c (revision 7417cfdecea1902cef03c0d61a72df97d945925d)
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