Print this page
3408 detect socket type of newer AMD CPUs
Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c
+++ new/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * "Generic AMD" model-specific support. If no more-specific support can
28 28 * be found, or such modules declines to initialize, then for AuthenticAMD
29 29 * cpus this module can have a crack at providing some AMD model-specific
30 30 * support that at least goes beyond common MCA architectural features
31 31 * if not down to the nitty-gritty level for a particular model. We
32 32 * are layered on top of a cpu module, likely cpu.generic, so there is no
33 33 * need for us to perform common architecturally-accessible functions.
34 34 */
35 35
36 36 #include <sys/types.h>
37 37 #include <sys/cmn_err.h>
38 38 #include <sys/modctl.h>
39 39 #include <sys/cpu_module.h>
40 40 #include <sys/mca_x86.h>
41 41 #include <sys/pci_cfgspace.h>
42 42 #include <sys/x86_archext.h>
43 43 #include <sys/mc_amd.h>
44 44 #include <sys/fm/protocol.h>
45 45 #include <sys/fm/cpu/GENAMD.h>
46 46 #include <sys/fm/smb/fmsmb.h>
47 47 #include <sys/fm/util.h>
48 48 #include <sys/nvpair.h>
49 49 #include <sys/controlregs.h>
50 50 #include <sys/pghw.h>
51 51 #include <sys/sunddi.h>
52 52 #include <sys/sysmacros.h>
53 53 #include <sys/cpu_module_ms_impl.h>
54 54
55 55 #include "authamd.h"
56 56
57 57 extern int x86gentopo_legacy; /* x86 generic topo support */
58 58
59 59 int authamd_ms_support_disable = 0;
60 60
61 61 #define AUTHAMD_F_REVS_BCDE \
62 62 (X86_CHIPREV_AMD_F_REV_B | X86_CHIPREV_AMD_F_REV_C0 | \
63 63 X86_CHIPREV_AMD_F_REV_CG | X86_CHIPREV_AMD_F_REV_D | \
64 64 X86_CHIPREV_AMD_F_REV_E)
65 65
66 66 #define AUTHAMD_F_REVS_FG \
67 67 (X86_CHIPREV_AMD_F_REV_F | X86_CHIPREV_AMD_F_REV_G)
68 68
69 69 #define AUTHAMD_10_REVS_AB \
70 70 (X86_CHIPREV_AMD_10_REV_A | X86_CHIPREV_AMD_10_REV_B)
71 71
72 72 /*
73 73 * Bitmasks of support for various features. Try to enable features
74 74 * via inclusion in one of these bitmasks and check that at the
75 75 * feature imlementation - that way new family support may often simply
76 76 * simply need to update these bitmasks.
77 77 */
78 78
79 79 /*
80 80 * Models that include an on-chip NorthBridge.
81 81 */
82 82 #define AUTHAMD_NBONCHIP(rev) \
83 83 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
84 84 X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
85 85
86 86 /*
87 87 * Families/revisions for which we can recognise main memory ECC errors.
88 88 */
89 89 #define AUTHAMD_MEMECC_RECOGNISED(rev) \
90 90 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
91 91 X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
92 92
93 93 /*
94 94 * Families/revisions that have an Online Spare Control Register
95 95 */
96 96 #define AUTHAMD_HAS_ONLINESPARECTL(rev) \
97 97 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) || \
98 98 X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
99 99
100 100 /*
101 101 * Families/revisions for which we will perform NB MCA Config changes
102 102 */
103 103 #define AUTHAMD_DO_NBMCACFG(rev) \
104 104 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
105 105 X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
106 106
107 107 /*
108 108 * Families/revisions that have chip cache scrubbers.
109 109 */
110 110 #define AUTHAMD_HAS_CHIPSCRUB(rev) \
111 111 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
112 112 X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
113 113
114 114 /*
115 115 * Families/revisions that have a NB misc register or registers -
116 116 * evaluates to 0 if no support, otherwise the number of MC4_MISCj.
117 117 */
118 118 #define AUTHAMD_NBMISC_NUM(rev) \
119 119 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F)? 1 : \
120 120 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A) ? 3 : 0))
121 121
122 122 /*
123 123 * Families/revision for which we wish not to machine check for GART
124 124 * table walk errors - bit 10 of NB CTL.
125 125 */
126 126 #define AUTHAMD_NOGARTTBLWLK_MC(rev) \
127 127 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
128 128 X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
129 129
↓ open down ↓ |
129 lines elided |
↑ open up ↑ |
130 130 /*
131 131 * Families/revisions that are potentially L3 capable
132 132 */
133 133 #define AUTHAMD_L3CAPABLE(rev) \
134 134 (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
135 135
136 136 /*
137 137 * Families/revisions that support x8 ChipKill ECC
138 138 */
139 139 #define AUTHAMD_SUPPORTS_X8ECC(rev) \
140 - (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_D))
140 + (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_D0))
141 141
142 142 /*
143 143 * We recognise main memory ECC errors for AUTHAMD_MEMECC_RECOGNISED
144 144 * revisions as:
145 145 *
146 146 * - being reported by the NB
147 147 * - being a compound bus/interconnect error (external to chip)
148 148 * - having LL of LG
149 149 * - having II of MEM (but could still be a master/target abort)
150 150 * - having CECC or UECC set
151 151 *
152 152 * We do not check the extended error code (first nibble of the
153 153 * model-specific error code on AMD) since this has changed from
154 154 * family 0xf to family 0x10 (ext code 0 now reserved on family 0x10).
155 155 * Instead we use CECC/UECC to separate off the master/target
156 156 * abort cases.
157 157 *
158 158 * We insist that the detector be the NorthBridge bank; although
159 159 * IC/DC can report some main memory errors, they do not capture
160 160 * an address at sufficient resolution to be useful and the NB will
161 161 * report most errors.
162 162 */
163 163 #define AUTHAMD_IS_MEMECCERR(bank, status) \
164 164 ((bank) == AMD_MCA_BANK_NB && \
165 165 MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && \
166 166 MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
167 167 MCAX86_ERRCODE_II(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_II_MEM && \
168 168 ((status) & (AMD_BANK_STAT_CECC | AMD_BANK_STAT_UECC)))
169 169
170 170 static authamd_error_disp_t authamd_memce_disp = {
171 171 FM_EREPORT_CPU_GENAMD,
172 172 FM_EREPORT_CPU_GENAMD_MEM_CE,
173 173 FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_CE
174 174 };
175 175
176 176 static authamd_error_disp_t authamd_memue_disp = {
177 177 FM_EREPORT_CPU_GENAMD,
178 178 FM_EREPORT_CPU_GENAMD_MEM_UE,
179 179 FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_UE
180 180 };
181 181
182 182 static authamd_error_disp_t authamd_ckmemce_disp = {
183 183 FM_EREPORT_CPU_GENAMD,
184 184 FM_EREPORT_CPU_GENAMD_CKMEM_CE,
185 185 FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_CE
186 186 };
187 187
188 188 static authamd_error_disp_t authamd_ckmemue_disp = {
189 189 FM_EREPORT_CPU_GENAMD,
190 190 FM_EREPORT_CPU_GENAMD_CKMEM_UE,
191 191 FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_UE
192 192 };
193 193
194 194 /*
195 195 * We recognise GART walk errors as:
196 196 *
197 197 * - being reported by the NB
198 198 * - being a compound TLB error
199 199 * - having LL of LG and TT of GEN
200 200 * - having UC set
201 201 * - possibly having PCC set (if source CPU)
202 202 */
203 203 #define AUTHAMD_IS_GARTERR(bank, status) \
204 204 ((bank) == AMD_MCA_BANK_NB && \
205 205 MCAX86_ERRCODE_ISTLB(MCAX86_ERRCODE(status)) && \
206 206 MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
207 207 MCAX86_ERRCODE_TT(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_TT_GEN && \
208 208 (status) & MSR_MC_STATUS_UC)
209 209
210 210 static authamd_error_disp_t authamd_gart_disp = {
211 211 FM_EREPORT_CPU_GENAMD, /* use generic subclass */
212 212 FM_EREPORT_CPU_GENADM_GARTTBLWLK, /* use generic leafclass */
213 213 0 /* no additional payload */
214 214 };
215 215
216 216
217 217 static struct authamd_nodeshared *authamd_shared[AUTHAMD_MAX_NODES];
218 218
219 219 static int
220 220 authamd_chip_once(authamd_data_t *authamd, enum authamd_cfgonce_bitnum what)
221 221 {
222 222 return (atomic_set_long_excl(&authamd->amd_shared->ans_cfgonce,
223 223 what) == 0 ? B_TRUE : B_FALSE);
224 224 }
225 225
226 226 static void
227 227 authamd_pcicfg_write(uint_t procnodeid, uint_t func, uint_t reg, uint32_t val)
228 228 {
229 229 ASSERT(procnodeid + 24 <= 31);
230 230 ASSERT((func & 7) == func);
231 231 ASSERT((reg & 3) == 0 && reg < 4096);
232 232
233 233 cmi_pci_putl(0, procnodeid + 24, func, reg, 0, val);
234 234 }
235 235
236 236 static uint32_t
237 237 authamd_pcicfg_read(uint_t procnodeid, uint_t func, uint_t reg)
238 238 {
239 239 ASSERT(procnodeid + 24 <= 31);
240 240 ASSERT((func & 7) == func);
241 241 ASSERT((reg & 3) == 0 && reg < 4096);
242 242
243 243 return (cmi_pci_getl(0, procnodeid + 24, func, reg, 0, 0));
244 244 }
245 245
246 246 void
247 247 authamd_bankstatus_prewrite(cmi_hdl_t hdl, authamd_data_t *authamd)
248 248 {
249 249 uint64_t hwcr;
250 250
251 251 if (cmi_hdl_rdmsr(hdl, MSR_AMD_HWCR, &hwcr) != CMI_SUCCESS)
252 252 return;
253 253
254 254 authamd->amd_hwcr = hwcr;
255 255
256 256 if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
257 257 hwcr |= AMD_HWCR_MCI_STATUS_WREN;
258 258 (void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
259 259 }
260 260 }
261 261
262 262 void
263 263 authamd_bankstatus_postwrite(cmi_hdl_t hdl, authamd_data_t *authamd)
264 264 {
265 265 uint64_t hwcr = authamd->amd_hwcr;
266 266
267 267 if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
268 268 hwcr &= ~AMD_HWCR_MCI_STATUS_WREN;
269 269 (void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
270 270 }
271 271 }
272 272
273 273 /*
274 274 * Read EccCnt repeatedly for all possible channel/chip-select combos:
275 275 *
276 276 * - read sparectl register
277 277 * - if EccErrCntWrEn is set, clear that bit in the just-read value
278 278 * and write it back to sparectl; this *may* clobber the EccCnt
279 279 * for the channel/chip-select combination currently selected, so
280 280 * we leave this bit clear if we had to clear it
281 281 * - cycle through all channel/chip-select combinations writing each
282 282 * combination to sparectl before reading the register back for
283 283 * EccCnt for that combination; since EccErrCntWrEn is clear
284 284 * the writes to select what count to read will not themselves
285 285 * zero any counts
286 286 */
287 287 static int
288 288 authamd_read_ecccnt(authamd_data_t *authamd, struct authamd_logout *msl)
289 289 {
290 290 union mcreg_sparectl sparectl;
291 291 uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
292 292 uint_t family = authamd->amd_shared->ans_family;
293 293 uint32_t rev = authamd->amd_shared->ans_rev;
294 294 int chan, cs;
295 295
296 296 /*
297 297 * Check for feature support; this macro will test down to the
298 298 * family revision number, whereafter we'll switch on family
299 299 * assuming that future revisions will use the same register
300 300 * format.
301 301 */
302 302 if (!AUTHAMD_HAS_ONLINESPARECTL(rev)) {
303 303 bzero(&msl->aal_eccerrcnt, sizeof (msl->aal_eccerrcnt));
304 304 return (0);
305 305 }
306 306
307 307 MCREG_VAL32(&sparectl) =
308 308 authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
309 309 MC_CTL_REG_SPARECTL);
310 310
311 311 switch (family) {
312 312 case AUTHAMD_FAMILY_F:
313 313 MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 0;
314 314 break;
315 315
316 316 case AUTHAMD_FAMILY_10:
317 317 MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 0;
318 318 break;
319 319 }
320 320
321 321 for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
322 322 switch (family) {
323 323 case AUTHAMD_FAMILY_F:
324 324 MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
325 325 chan;
326 326 break;
327 327
328 328 case AUTHAMD_FAMILY_10:
329 329 MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
330 330 chan;
331 331 break;
332 332 }
333 333
334 334 for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
335 335 switch (family) {
336 336 case AUTHAMD_FAMILY_F:
337 337 MCREG_FIELD_F_revFG(&sparectl,
338 338 EccErrCntDramCs) = cs;
339 339 break;
340 340
341 341 case AUTHAMD_FAMILY_10:
342 342 MCREG_FIELD_10_revAB(&sparectl,
343 343 EccErrCntDramCs) = cs;
344 344 break;
345 345 }
346 346
347 347 authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
348 348 MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
349 349
350 350 MCREG_VAL32(&sparectl) = authamd_pcicfg_read(procnodeid,
351 351 MC_FUNC_MISCCTL, MC_CTL_REG_SPARECTL);
352 352
353 353 switch (family) {
354 354 case AUTHAMD_FAMILY_F:
355 355 msl->aal_eccerrcnt[chan][cs] =
356 356 MCREG_FIELD_F_revFG(&sparectl, EccErrCnt);
357 357 break;
358 358 case AUTHAMD_FAMILY_10:
359 359 msl->aal_eccerrcnt[chan][cs] =
360 360 MCREG_FIELD_10_revAB(&sparectl, EccErrCnt);
361 361 break;
362 362 }
363 363 }
364 364 }
365 365
366 366 return (1);
367 367 }
368 368
369 369 /*
370 370 * Clear EccCnt for all possible channel/chip-select combos:
371 371 *
372 372 * - set EccErrCntWrEn in sparectl, if necessary
373 373 * - write 0 to EccCnt for all channel/chip-select combinations
374 374 * - clear EccErrCntWrEn
375 375 *
376 376 * If requested also disable the interrupts taken on counter overflow
377 377 * and on swap done.
378 378 */
379 379 static void
380 380 authamd_clear_ecccnt(authamd_data_t *authamd, boolean_t clrint)
381 381 {
382 382 union mcreg_sparectl sparectl;
383 383 uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
384 384 uint_t family = authamd->amd_shared->ans_family;
385 385 uint32_t rev = authamd->amd_shared->ans_rev;
386 386 int chan, cs;
387 387
388 388 if (!AUTHAMD_HAS_ONLINESPARECTL(rev))
389 389 return;
390 390
391 391 MCREG_VAL32(&sparectl) =
392 392 authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
393 393 MC_CTL_REG_SPARECTL);
394 394
395 395 switch (family) {
396 396 case AUTHAMD_FAMILY_F:
397 397 MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 1;
398 398 if (clrint) {
399 399 MCREG_FIELD_F_revFG(&sparectl, EccErrInt) = 0;
400 400 MCREG_FIELD_F_revFG(&sparectl, SwapDoneInt) = 0;
401 401 }
402 402 break;
403 403
404 404 case AUTHAMD_FAMILY_10:
405 405 MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 1;
406 406 if (clrint) {
407 407 MCREG_FIELD_10_revAB(&sparectl, EccErrInt) = 0;
408 408 MCREG_FIELD_10_revAB(&sparectl, SwapDoneInt) = 0;
409 409 }
410 410 break;
411 411 }
412 412
413 413 authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
414 414 MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
415 415
416 416 for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
417 417 switch (family) {
418 418 case AUTHAMD_FAMILY_F:
419 419 MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
420 420 chan;
421 421 break;
422 422
423 423 case AUTHAMD_FAMILY_10:
424 424 MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
425 425 chan;
426 426 break;
427 427 }
428 428
429 429 for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
430 430 switch (family) {
431 431 case AUTHAMD_FAMILY_F:
432 432 MCREG_FIELD_F_revFG(&sparectl,
433 433 EccErrCntDramCs) = cs;
434 434 MCREG_FIELD_F_revFG(&sparectl,
435 435 EccErrCnt) = 0;
436 436 break;
437 437
438 438 case AUTHAMD_FAMILY_10:
439 439 MCREG_FIELD_10_revAB(&sparectl,
440 440 EccErrCntDramCs) = cs;
441 441 MCREG_FIELD_10_revAB(&sparectl,
442 442 EccErrCnt) = 0;
443 443 break;
444 444 }
445 445
446 446 authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
447 447 MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
448 448 }
449 449 }
450 450 }
451 451
452 452
453 453 /*
454 454 * Return
455 455 * 1: supported
456 456 * 0: unsupported
457 457 */
458 458 static int
459 459 authamd_supported(cmi_hdl_t hdl)
460 460 {
461 461 uint_t family = cmi_hdl_family(hdl);
462 462
463 463 switch (family) {
464 464 case AUTHAMD_FAMILY_6:
465 465 case AUTHAMD_FAMILY_F:
466 466 case AUTHAMD_FAMILY_10:
467 467 return (1);
468 468 default:
469 469 return (0);
470 470 }
471 471 }
472 472
473 473 /*
474 474 * cms_init entry point.
475 475 *
476 476 * This module provides broad model-specific support for AMD families
477 477 * 0x6, 0xf and 0x10. Future families will have to be evaluated once their
478 478 * documentation is available.
479 479 */
480 480 int
481 481 authamd_init(cmi_hdl_t hdl, void **datap)
482 482 {
483 483 uint_t chipid = cmi_hdl_chipid(hdl);
484 484 uint_t procnodeid = cmi_hdl_procnodeid(hdl);
485 485 struct authamd_nodeshared *sp, *osp;
486 486 uint_t family = cmi_hdl_family(hdl);
487 487 uint32_t rev = cmi_hdl_chiprev(hdl);
488 488 authamd_data_t *authamd;
489 489 uint64_t cap;
490 490
491 491 if (authamd_ms_support_disable ||
492 492 !authamd_supported(hdl))
493 493 return (ENOTSUP);
494 494
495 495 if (!is_x86_feature(x86_featureset, X86FSET_MCA))
496 496 return (ENOTSUP);
497 497
498 498 if (cmi_hdl_rdmsr(hdl, IA32_MSR_MCG_CAP, &cap) != CMI_SUCCESS)
499 499 return (ENOTSUP);
500 500
501 501 if (!(cap & MCG_CAP_CTL_P))
502 502 return (ENOTSUP);
503 503
504 504 authamd = *datap = kmem_zalloc(sizeof (authamd_data_t), KM_SLEEP);
505 505 cmi_hdl_hold(hdl); /* release in fini */
506 506 authamd->amd_hdl = hdl;
507 507
508 508 if ((sp = authamd_shared[procnodeid]) == NULL) {
509 509 sp = kmem_zalloc(sizeof (struct authamd_nodeshared), KM_SLEEP);
510 510 sp->ans_chipid = chipid;
511 511 sp->ans_procnodeid = procnodeid;
512 512 sp->ans_family = family;
513 513 sp->ans_rev = rev;
514 514 membar_producer();
515 515
516 516 osp = atomic_cas_ptr(&authamd_shared[procnodeid], NULL, sp);
517 517 if (osp != NULL) {
518 518 kmem_free(sp, sizeof (struct authamd_nodeshared));
519 519 sp = osp;
520 520 }
521 521 }
522 522 authamd->amd_shared = sp;
523 523
524 524 return (0);
525 525 }
526 526
527 527 /*
528 528 * cms_logout_size entry point.
529 529 */
530 530 /*ARGSUSED*/
531 531 size_t
532 532 authamd_logout_size(cmi_hdl_t hdl)
533 533 {
534 534 return (sizeof (struct authamd_logout));
535 535 }
536 536
537 537 /*
538 538 * cms_mcgctl_val entry point
539 539 *
540 540 * Instead of setting all bits to 1 we can set just those for the
541 541 * error detector banks known to exist.
542 542 */
543 543 /*ARGSUSED*/
544 544 uint64_t
545 545 authamd_mcgctl_val(cmi_hdl_t hdl, int nbanks, uint64_t proposed)
546 546 {
547 547 return (nbanks < 64 ? (1ULL << nbanks) - 1 : proposed);
548 548 }
549 549
550 550 /*
551 551 * cms_bankctl_skipinit entry point
552 552 *
553 553 * On K6 we do not initialize MC0_CTL since, reportedly, this bank (for DC)
554 554 * may produce spurious machine checks.
555 555 *
556 556 * Only allow a single core to setup the NorthBridge MCi_CTL register.
557 557 */
558 558 /*ARGSUSED*/
559 559 boolean_t
560 560 authamd_bankctl_skipinit(cmi_hdl_t hdl, int bank)
561 561 {
562 562 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
563 563 uint32_t rev = authamd->amd_shared->ans_rev;
564 564
565 565 if (authamd->amd_shared->ans_family == AUTHAMD_FAMILY_6)
566 566 return (bank == 0 ? B_TRUE : B_FALSE);
567 567
568 568 if (AUTHAMD_NBONCHIP(rev) && bank == AMD_MCA_BANK_NB) {
569 569 return (authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBMCA) ==
570 570 B_TRUE ? B_FALSE : B_TRUE);
571 571 }
572 572
573 573 return (B_FALSE);
574 574 }
575 575
576 576 /*
577 577 * cms_bankctl_val entry point
578 578 */
579 579 uint64_t
580 580 authamd_bankctl_val(cmi_hdl_t hdl, int bank, uint64_t proposed)
581 581 {
582 582 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
583 583 uint32_t rev = authamd->amd_shared->ans_rev;
584 584 uint64_t val = proposed;
585 585
586 586 /*
587 587 * The Intel MCA says we can write all 1's to enable #MC for
588 588 * all errors, and AMD docs say much the same. But, depending
589 589 * perhaps on other config registers, taking machine checks
590 590 * for some errors such as GART TLB errors and master/target
591 591 * aborts may be bad - they set UC and sometime also PCC, but
592 592 * we should not always panic for these error types.
593 593 *
594 594 * Our cms_error_action entry point can suppress such panics,
595 595 * however we can also use the cms_bankctl_val entry point to
596 596 * veto enabling of some of the known villains in the first place.
597 597 */
598 598 if (bank == AMD_MCA_BANK_NB && AUTHAMD_NOGARTTBLWLK_MC(rev))
599 599 val &= ~AMD_NB_EN_GARTTBLWK;
600 600
601 601 return (val);
602 602 }
603 603
604 604 /*
605 605 * Bits to add to NB MCA config (after watchdog config).
606 606 */
607 607 uint32_t authamd_nb_mcacfg_add = AMD_NB_CFG_ADD_CMN;
608 608
609 609 /*
610 610 * Bits to remove from NB MCA config (after watchdog config)
611 611 */
612 612 uint32_t authamd_nb_mcacfg_remove = AMD_NB_CFG_REMOVE_CMN;
613 613
614 614 /*
615 615 * NB Watchdog policy, and rate we use if enabling.
616 616 */
617 617 enum {
618 618 AUTHAMD_NB_WDOG_LEAVEALONE,
619 619 AUTHAMD_NB_WDOG_DISABLE,
620 620 AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED,
621 621 AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE
622 622 } authamd_nb_watchdog_policy = AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED;
623 623
624 624 uint32_t authamd_nb_mcacfg_wdog = AMD_NB_CFG_WDOGTMRCNTSEL_4095 |
625 625 AMD_NB_CFG_WDOGTMRBASESEL_1MS;
626 626
627 627 /*
628 628 * Per-core cache scrubbing policy and rates.
629 629 */
630 630 enum {
631 631 AUTHAMD_SCRUB_BIOSDEFAULT, /* leave as BIOS configured */
632 632 AUTHAMD_SCRUB_FIXED, /* assign our chosen rate */
633 633 AUTHAMD_SCRUB_MAX /* use higher of ours and BIOS rate */
634 634 } authamd_scrub_policy = AUTHAMD_SCRUB_MAX;
635 635
636 636 uint32_t authamd_scrub_rate_dcache = 0xf; /* 64K per 0.67 seconds */
637 637 uint32_t authamd_scrub_rate_l2cache = 0xe; /* 1MB per 5.3 seconds */
638 638 uint32_t authamd_scrub_rate_l3cache = 0xd; /* 1MB per 2.7 seconds */
639 639
640 640 static uint32_t
641 641 authamd_scrubrate(uint32_t osrate, uint32_t biosrate, const char *varnm)
642 642 {
643 643 uint32_t rate;
644 644
645 645 if (osrate > AMD_NB_SCRUBCTL_RATE_MAX) {
646 646 cmn_err(CE_WARN, "%s is too large, resetting to 0x%x\n",
647 647 varnm, AMD_NB_SCRUBCTL_RATE_MAX);
648 648 osrate = AMD_NB_SCRUBCTL_RATE_MAX;
649 649 }
650 650
651 651 switch (authamd_scrub_policy) {
652 652 case AUTHAMD_SCRUB_FIXED:
653 653 rate = osrate;
654 654 break;
655 655
656 656 default:
657 657 cmn_err(CE_WARN, "Unknown authamd_scrub_policy %d - "
658 658 "using default policy of AUTHAMD_SCRUB_MAX",
659 659 authamd_scrub_policy);
660 660 /*FALLTHRU*/
661 661
662 662 case AUTHAMD_SCRUB_MAX:
663 663 if (osrate != 0 && biosrate != 0)
664 664 rate = MIN(osrate, biosrate); /* small is fast */
665 665 else
666 666 rate = osrate ? osrate : biosrate;
667 667 }
668 668
669 669 return (rate);
670 670 }
671 671
672 672 /*
673 673 * cms_mca_init entry point.
674 674 */
675 675 /*ARGSUSED*/
676 676 void
677 677 authamd_mca_init(cmi_hdl_t hdl, int nbanks)
678 678 {
679 679 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
680 680 uint32_t rev = authamd->amd_shared->ans_rev;
681 681 uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
682 682
683 683 /*
684 684 * On chips with a NB online spare control register take control
685 685 * and clear ECC counts.
686 686 */
687 687 if (AUTHAMD_HAS_ONLINESPARECTL(rev) &&
688 688 authamd_chip_once(authamd, AUTHAMD_CFGONCE_ONLNSPRCFG)) {
689 689 authamd_clear_ecccnt(authamd, B_TRUE);
690 690 }
691 691
692 692 /*
693 693 * And since we are claiming the telemetry stop the BIOS receiving
694 694 * an SMI on NB threshold overflow.
695 695 */
696 696 if (AUTHAMD_NBMISC_NUM(rev) &&
697 697 authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBTHRESH)) {
698 698 union mcmsr_nbmisc nbm;
699 699 int i;
700 700
701 701 authamd_bankstatus_prewrite(hdl, authamd);
702 702
703 703 for (i = 0; i < AUTHAMD_NBMISC_NUM(rev); i++) {
704 704 if (cmi_hdl_rdmsr(hdl, MC_MSR_NB_MISC(i),
705 705 (uint64_t *)&nbm) != CMI_SUCCESS)
706 706 continue;
707 707
708 708 if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) &&
709 709 MCMSR_FIELD_F_revFG(&nbm, mcmisc_Valid) &&
710 710 MCMSR_FIELD_F_revFG(&nbm, mcmisc_CntP)) {
711 711 MCMSR_FIELD_F_revFG(&nbm, mcmisc_IntType) = 0;
712 712 } else if (X86_CHIPREV_ATLEAST(rev,
713 713 X86_CHIPREV_AMD_10_REV_A) &&
714 714 MCMSR_FIELD_10_revAB(&nbm, mcmisc_Valid) &&
715 715 MCMSR_FIELD_10_revAB(&nbm, mcmisc_CntP)) {
716 716 MCMSR_FIELD_10_revAB(&nbm, mcmisc_IntType) = 0;
717 717 }
718 718
719 719 (void) cmi_hdl_wrmsr(hdl, MC_MSR_NB_MISC(i),
720 720 MCMSR_VAL(&nbm));
721 721 }
722 722
723 723 authamd_bankstatus_postwrite(hdl, authamd);
724 724 }
725 725
726 726 /*
727 727 * NB MCA Configuration Register.
728 728 */
729 729 if (AUTHAMD_DO_NBMCACFG(rev) &&
730 730 authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBMCACFG)) {
731 731 uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
732 732 MC_CTL_REG_NBCFG);
733 733
734 734 switch (authamd_nb_watchdog_policy) {
735 735 case AUTHAMD_NB_WDOG_LEAVEALONE:
736 736 break;
737 737
738 738 case AUTHAMD_NB_WDOG_DISABLE:
739 739 val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK |
740 740 AMD_NB_CFG_WDOGTMRCNTSEL_MASK);
741 741 val |= AMD_NB_CFG_WDOGTMRDIS;
742 742 break;
743 743
744 744 default:
745 745 cmn_err(CE_NOTE, "authamd_nb_watchdog_policy=%d "
746 746 "unrecognised, using default policy",
747 747 authamd_nb_watchdog_policy);
748 748 /*FALLTHRU*/
749 749
750 750 case AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED:
751 751 if (!(val & AMD_NB_CFG_WDOGTMRDIS))
752 752 break; /* if enabled leave rate intact */
753 753 /*FALLTHRU*/
754 754
755 755 case AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE:
756 756 val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK |
757 757 AMD_NB_CFG_WDOGTMRCNTSEL_MASK |
758 758 AMD_NB_CFG_WDOGTMRDIS);
759 759 val |= authamd_nb_mcacfg_wdog;
760 760 break;
761 761 }
762 762
763 763 /*
764 764 * Bit 0 of the NB MCA Config register is reserved on family
765 765 * 0x10.
766 766 */
767 767 if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
768 768 authamd_nb_mcacfg_add &= ~AMD_NB_CFG_CPUECCERREN;
769 769
770 770 val &= ~authamd_nb_mcacfg_remove;
771 771 val |= authamd_nb_mcacfg_add;
772 772
773 773 authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
774 774 MC_CTL_REG_NBCFG, val);
775 775 }
776 776
777 777 /*
778 778 * Cache scrubbing. We can't enable DRAM scrubbing since
779 779 * we don't know the DRAM base for this node.
780 780 */
781 781 if (AUTHAMD_HAS_CHIPSCRUB(rev) &&
782 782 authamd_scrub_policy != AUTHAMD_SCRUB_BIOSDEFAULT &&
783 783 authamd_chip_once(authamd, AUTHAMD_CFGONCE_CACHESCRUB)) {
784 784 uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
785 785 MC_CTL_REG_SCRUBCTL);
786 786 int l3cap = 0;
787 787
788 788 if (AUTHAMD_L3CAPABLE(rev)) {
789 789 l3cap = (authamd_pcicfg_read(procnodeid,
790 790 MC_FUNC_MISCCTL, MC_CTL_REG_NBCAP) &
791 791 MC_NBCAP_L3CAPABLE) != 0;
792 792 }
793 793
794 794 authamd_scrub_rate_dcache =
795 795 authamd_scrubrate(authamd_scrub_rate_dcache,
796 796 (val & AMD_NB_SCRUBCTL_DC_MASK) >> AMD_NB_SCRUBCTL_DC_SHIFT,
797 797 "authamd_scrub_rate_dcache");
798 798
799 799 authamd_scrub_rate_l2cache =
800 800 authamd_scrubrate(authamd_scrub_rate_l2cache,
801 801 (val & AMD_NB_SCRUBCTL_L2_MASK) >> AMD_NB_SCRUBCTL_L2_SHIFT,
802 802 "authamd_scrub_rate_l2cache");
803 803
804 804 authamd_scrub_rate_l3cache = l3cap ?
805 805 authamd_scrubrate(authamd_scrub_rate_l3cache,
806 806 (val & AMD_NB_SCRUBCTL_L3_MASK) >> AMD_NB_SCRUBCTL_L3_SHIFT,
807 807 "authamd_scrub_rate_l3cache") : 0;
808 808
809 809 val = AMD_NB_MKSCRUBCTL(authamd_scrub_rate_l3cache,
810 810 authamd_scrub_rate_dcache, authamd_scrub_rate_l2cache,
811 811 val & AMD_NB_SCRUBCTL_DRAM_MASK);
812 812
813 813 authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
814 814 MC_CTL_REG_SCRUBCTL, val);
815 815 }
816 816
817 817 /*
818 818 * ECC symbol size. Defaults to 4.
819 819 * Set to 8 on systems that support x8 ECC and have it enabled.
820 820 */
821 821 if (authamd_chip_once(authamd, AUTHAMD_CFGONCE_ECCSYMSZ)) {
822 822 authamd->amd_shared->ans_eccsymsz = "C4";
823 823 if (AUTHAMD_SUPPORTS_X8ECC(rev) &&
824 824 (authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
825 825 MC_CTL_REG_EXTNBCFG) & MC_EXTNBCFG_ECCSYMSZ))
826 826 authamd->amd_shared->ans_eccsymsz = "C8";
827 827 }
828 828 }
829 829
830 830 /*
831 831 * cms_poll_ownermask entry point.
832 832 */
833 833 uint64_t
834 834 authamd_poll_ownermask(cmi_hdl_t hdl, hrtime_t pintvl)
835 835 {
836 836 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
837 837 struct authamd_nodeshared *ansp = authamd->amd_shared;
838 838 hrtime_t now = gethrtime_waitfree();
839 839 hrtime_t last = ansp->ans_poll_timestamp;
840 840 int dopoll = 0;
841 841
842 842 if (now - last > 2 * pintvl || last == 0) {
843 843 ansp->ans_pollowner = hdl;
844 844 dopoll = 1;
845 845 } else if (ansp->ans_pollowner == hdl) {
846 846 dopoll = 1;
847 847 }
848 848
849 849 if (dopoll)
850 850 ansp->ans_poll_timestamp = now;
851 851
852 852 return (dopoll ? -1ULL : ~(1 << AMD_MCA_BANK_NB));
853 853
854 854 }
855 855
856 856 /*
857 857 * cms_bank_logout entry point.
858 858 */
859 859 /*ARGSUSED*/
860 860 void
861 861 authamd_bank_logout(cmi_hdl_t hdl, int bank, uint64_t status,
862 862 uint64_t addr, uint64_t misc, void *mslogout)
863 863 {
864 864 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
865 865 struct authamd_logout *msl = mslogout;
866 866 uint32_t rev = authamd->amd_shared->ans_rev;
867 867
868 868 if (msl == NULL)
869 869 return;
870 870
871 871 /*
872 872 * For main memory ECC errors on revisions with an Online Spare
873 873 * Control Register grab the ECC counts by channel and chip-select
874 874 * and reset them to 0.
875 875 */
876 876 if (AUTHAMD_MEMECC_RECOGNISED(rev) &&
877 877 AUTHAMD_IS_MEMECCERR(bank, status) &&
878 878 AUTHAMD_HAS_ONLINESPARECTL(rev)) {
879 879 if (authamd_read_ecccnt(authamd, msl))
880 880 authamd_clear_ecccnt(authamd, B_FALSE);
881 881 }
882 882 }
883 883
884 884 /*
885 885 * cms_error_action entry point
886 886 */
887 887
888 888 int authamd_forgive_uc = 0; /* For test/debug only */
889 889 int authamd_forgive_pcc = 0; /* For test/debug only */
890 890 int authamd_fake_poison = 0; /* For test/debug only */
891 891
892 892 /*ARGSUSED*/
893 893 uint32_t
894 894 authamd_error_action(cmi_hdl_t hdl, int ismc, int bank,
895 895 uint64_t status, uint64_t addr, uint64_t misc, void *mslogout)
896 896 {
897 897 authamd_error_disp_t *disp;
898 898 uint32_t rv = 0;
899 899
900 900 if (authamd_forgive_uc)
901 901 rv |= CMS_ERRSCOPE_CLEARED_UC;
902 902
903 903 if (authamd_forgive_pcc)
904 904 rv |= CMS_ERRSCOPE_CURCONTEXT_OK;
905 905
906 906 if (authamd_fake_poison && status & MSR_MC_STATUS_UC)
907 907 rv |= CMS_ERRSCOPE_POISONED;
908 908
909 909 if (rv)
910 910 return (rv);
911 911
912 912 disp = authamd_disp_match(hdl, ismc, bank, status, addr, misc,
913 913 mslogout);
914 914
915 915 if (disp == &authamd_gart_disp) {
916 916 /*
917 917 * GART walk errors set UC and possibly PCC (if source CPU)
918 918 * but should not be regarded as terminal.
919 919 */
920 920 return (CMS_ERRSCOPE_IGNORE_ERR);
921 921 }
922 922
923 923 /*
924 924 * May also want to consider master abort and target abort. These
925 925 * also set UC and PCC (if src CPU) but the requester gets -1
926 926 * and I believe the IO stuff in Solaris will handle that.
927 927 */
928 928
929 929 return (rv);
930 930 }
931 931
932 932 /*
933 933 * cms_disp_match entry point
934 934 */
935 935 /*ARGSUSED*/
936 936 cms_cookie_t
937 937 authamd_disp_match(cmi_hdl_t hdl, int ismc, int bank, uint64_t status,
938 938 uint64_t addr, uint64_t misc, void *mslogout)
939 939 {
940 940 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
941 941 /* uint16_t errcode = MCAX86_ERRCODE(status); */
942 942 uint16_t exterrcode = AMD_EXT_ERRCODE(status);
943 943 uint32_t rev = authamd->amd_shared->ans_rev;
944 944
945 945 /*
946 946 * Recognise main memory ECC errors
947 947 */
948 948 if (AUTHAMD_MEMECC_RECOGNISED(rev) &&
949 949 AUTHAMD_IS_MEMECCERR(bank, status)) {
950 950 if (status & AMD_BANK_STAT_CECC) {
951 951 return (exterrcode == 0 ? &authamd_memce_disp :
952 952 &authamd_ckmemce_disp);
953 953 } else if (status & AMD_BANK_STAT_UECC) {
954 954 return (exterrcode == 0 ? &authamd_memue_disp :
955 955 &authamd_ckmemue_disp);
956 956 }
957 957 }
958 958
959 959 /*
960 960 * Recognise GART walk errors
961 961 */
962 962 if (AUTHAMD_NOGARTTBLWLK_MC(rev) && AUTHAMD_IS_GARTERR(bank, status))
963 963 return (&authamd_gart_disp);
964 964
965 965 return (NULL);
966 966 }
967 967
968 968 /*
969 969 * cms_ereport_class entry point
970 970 */
971 971 /*ARGSUSED*/
972 972 void
973 973 authamd_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie,
974 974 const char **cpuclsp, const char **leafclsp)
975 975 {
976 976 const authamd_error_disp_t *aed = mscookie;
977 977
978 978 if (aed == NULL)
979 979 return;
980 980
981 981 if (aed->aad_subclass != NULL)
982 982 *cpuclsp = aed->aad_subclass;
983 983 if (aed->aad_leafclass != NULL)
984 984 *leafclsp = aed->aad_leafclass;
985 985 }
986 986
987 987 /*ARGSUSED*/
988 988 static void
989 989 authamd_ereport_add_resource(cmi_hdl_t hdl, authamd_data_t *authamd,
990 990 nvlist_t *ereport, nv_alloc_t *nva, void *mslogout)
991 991 {
992 992 nvlist_t *elems[AUTHAMD_DRAM_NCHANNEL * AUTHAMD_DRAM_NCS];
993 993 uint8_t counts[AUTHAMD_DRAM_NCHANNEL * AUTHAMD_DRAM_NCS];
994 994 authamd_logout_t *msl;
995 995 nvlist_t *nvl;
996 996 int nelems = 0;
997 997 int i, chan, cs, mc;
998 998 nvlist_t *board_list = NULL;
999 999
1000 1000 if ((msl = mslogout) == NULL)
1001 1001 return;
1002 1002
1003 1003 /* Assume all processors have the same number of nodes */
1004 1004 mc = authamd->amd_shared->ans_procnodeid %
1005 1005 cpuid_get_procnodes_per_pkg(CPU);
1006 1006
1007 1007 for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
1008 1008 for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
1009 1009 if (msl->aal_eccerrcnt[chan][cs] == 0)
1010 1010 continue;
1011 1011
1012 1012 if ((nvl = fm_nvlist_create(nva)) == NULL)
1013 1013 continue;
1014 1014
1015 1015 elems[nelems] = nvl;
1016 1016 counts[nelems++] = msl->aal_eccerrcnt[chan][cs];
1017 1017
1018 1018 if (!x86gentopo_legacy) {
1019 1019 board_list = cmi_hdl_smb_bboard(hdl);
1020 1020 if (board_list == NULL)
1021 1021 continue;
1022 1022 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION,
1023 1023 NULL, NULL, board_list, 4,
1024 1024 "chip", cmi_hdl_smb_chipid(hdl),
1025 1025 "memory-controller", 0,
1026 1026 "dram-channel", chan,
1027 1027 "chip-select", cs);
1028 1028 } else {
1029 1029 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION,
1030 1030 NULL, NULL, 5,
1031 1031 "motherboard", 0,
1032 1032 "chip", authamd->amd_shared->ans_chipid,
1033 1033 "memory-controller", mc,
1034 1034 "dram-channel", chan,
1035 1035 "chip-select", cs);
1036 1036 }
1037 1037 }
1038 1038 }
1039 1039
1040 1040 if (nelems == 0)
1041 1041 return;
1042 1042
1043 1043 fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_RESOURCE,
1044 1044 DATA_TYPE_NVLIST_ARRAY, nelems, elems,
1045 1045 NULL);
1046 1046
1047 1047 fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_RESOURCECNT,
1048 1048 DATA_TYPE_UINT8_ARRAY, nelems, &counts[0],
1049 1049 NULL);
1050 1050
1051 1051 for (i = 0; i < nelems; i++)
1052 1052 fm_nvlist_destroy(elems[i], nva ? FM_NVA_RETAIN : FM_NVA_FREE);
1053 1053 }
1054 1054
1055 1055 /*
1056 1056 * cms_ereport_add_logout entry point
1057 1057 */
1058 1058 /*ARGSUSED*/
1059 1059 void
1060 1060 authamd_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *ereport, nv_alloc_t *nva,
1061 1061 int bank, uint64_t status, uint64_t addr, uint64_t misc,
1062 1062 void *mslogout, cms_cookie_t mscookie)
1063 1063 {
1064 1064 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
1065 1065 const authamd_error_disp_t *aed = mscookie;
1066 1066 uint64_t members;
1067 1067
1068 1068 if (aed == NULL)
1069 1069 return;
1070 1070
1071 1071 members = aed->aad_ereport_members;
1072 1072
1073 1073 if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYND) {
1074 1074 fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_SYND,
1075 1075 DATA_TYPE_UINT16, (uint16_t)AMD_BANK_SYND(status),
1076 1076 NULL);
1077 1077
1078 1078 if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYNDTYPE) {
1079 1079 fm_payload_set(ereport,
1080 1080 FM_EREPORT_GENAMD_PAYLOAD_NAME_SYNDTYPE,
1081 1081 DATA_TYPE_STRING, "E",
1082 1082 NULL);
1083 1083 }
1084 1084 }
1085 1085
1086 1086 if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_CKSYND) {
1087 1087 fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_CKSYND,
1088 1088 DATA_TYPE_UINT16, (uint16_t)AMD_NB_STAT_CKSYND(status),
1089 1089 NULL);
1090 1090
1091 1091 if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYNDTYPE) {
1092 1092 fm_payload_set(ereport,
1093 1093 FM_EREPORT_GENAMD_PAYLOAD_NAME_SYNDTYPE,
1094 1094 DATA_TYPE_STRING, authamd->amd_shared->ans_eccsymsz,
1095 1095 NULL);
1096 1096 }
1097 1097 }
1098 1098
1099 1099 if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_RESOURCE &&
1100 1100 status & MSR_MC_STATUS_ADDRV) {
1101 1101 authamd_ereport_add_resource(hdl, authamd, ereport, nva,
1102 1102 mslogout);
1103 1103 }
1104 1104 }
1105 1105
1106 1106 /*
1107 1107 * cms_msrinject entry point
1108 1108 */
1109 1109 cms_errno_t
1110 1110 authamd_msrinject(cmi_hdl_t hdl, uint_t msr, uint64_t val)
1111 1111 {
1112 1112 authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
1113 1113 cms_errno_t rv = CMSERR_BADMSRWRITE;
1114 1114
1115 1115 authamd_bankstatus_prewrite(hdl, authamd);
1116 1116 if (cmi_hdl_wrmsr(hdl, msr, val) == CMI_SUCCESS)
1117 1117 rv = CMS_SUCCESS;
1118 1118 authamd_bankstatus_postwrite(hdl, authamd);
1119 1119
1120 1120 return (rv);
1121 1121 }
1122 1122
1123 1123 cms_api_ver_t _cms_api_version = CMS_API_VERSION_2;
1124 1124
1125 1125 const cms_ops_t _cms_ops = {
1126 1126 authamd_init, /* cms_init */
1127 1127 NULL, /* cms_post_startup */
1128 1128 NULL, /* cms_post_mpstartup */
1129 1129 authamd_logout_size, /* cms_logout_size */
1130 1130 authamd_mcgctl_val, /* cms_mcgctl_val */
1131 1131 authamd_bankctl_skipinit, /* cms_bankctl_skipinit */
1132 1132 authamd_bankctl_val, /* cms_bankctl_val */
1133 1133 NULL, /* cms_bankstatus_skipinit */
1134 1134 NULL, /* cms_bankstatus_val */
1135 1135 authamd_mca_init, /* cms_mca_init */
1136 1136 authamd_poll_ownermask, /* cms_poll_ownermask */
1137 1137 authamd_bank_logout, /* cms_bank_logout */
1138 1138 authamd_error_action, /* cms_error_action */
1139 1139 authamd_disp_match, /* cms_disp_match */
1140 1140 authamd_ereport_class, /* cms_ereport_class */
1141 1141 NULL, /* cms_ereport_detector */
1142 1142 NULL, /* cms_ereport_includestack */
1143 1143 authamd_ereport_add_logout, /* cms_ereport_add_logout */
1144 1144 authamd_msrinject, /* cms_msrinject */
1145 1145 NULL, /* cms_fini */
1146 1146 };
1147 1147
1148 1148 static struct modlcpu modlcpu = {
1149 1149 &mod_cpuops,
1150 1150 "Generic AMD model-specific MCA"
1151 1151 };
1152 1152
1153 1153 static struct modlinkage modlinkage = {
1154 1154 MODREV_1,
1155 1155 (void *)&modlcpu,
1156 1156 NULL
1157 1157 };
1158 1158
1159 1159 int
1160 1160 _init(void)
1161 1161 {
1162 1162 return (mod_install(&modlinkage));
1163 1163 }
1164 1164
1165 1165 int
1166 1166 _info(struct modinfo *modinfop)
1167 1167 {
1168 1168 return (mod_info(&modlinkage, modinfop));
1169 1169 }
1170 1170
1171 1171 int
1172 1172 _fini(void)
1173 1173 {
1174 1174 return (mod_remove(&modlinkage));
1175 1175 }
↓ open down ↓ |
1025 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX