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