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
gintel_init(cmi_hdl_t hdl,void ** datap)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
gintel_error_action(cmi_hdl_t hdl,int ismc,int bank,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)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
gintel_disp_match(cmi_hdl_t hdl,int ismc,int bank,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)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
gintel_ereport_class(cmi_hdl_t hdl,cms_cookie_t mscookie,const char ** cpuclsp,const char ** leafclsp)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 *
gintel_gentopo_ereport_detector(cmi_hdl_t hdl,cms_cookie_t mscookie,nv_alloc_t * nva)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 *
gintel_ereport_detector(cmi_hdl_t hdl,int bankno,cms_cookie_t mscookie,nv_alloc_t * nva)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 *
gintel_gentopo_ereport_create_resource_elem(cmi_hdl_t hdl,nv_alloc_t * nva,mc_unum_t * unump)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 *
gintel_ereport_create_resource_elem(nv_alloc_t * nva,mc_unum_t * unump)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
nehalem_ep_ereport_add_memory_error_counter(uint_t chipid,uint32_t * this_err_counter_array)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
gintel_cpu_generation(cmi_hdl_t hdl)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
gintel_ereport_add_logout(cmi_hdl_t hdl,nvlist_t * ereport,nv_alloc_t * nva,int banknum,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout,cms_cookie_t mscookie)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
gintel_bankctl_skipinit(cmi_hdl_t hdl,int banknum)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
_init(void)611 _init(void)
612 {
613 return (mod_install(&modlinkage));
614 }
615
616 int
_info(struct modinfo * modinfop)617 _info(struct modinfo *modinfop)
618 {
619 return (mod_info(&modlinkage, modinfop));
620 }
621
622 int
_fini(void)623 _fini(void)
624 {
625 return (mod_remove(&modlinkage));
626 }
627