summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorAdrian Frost <Adrian.Frost@Sun.COM>2008-08-18 01:27:34 -0700
committerAdrian Frost <Adrian.Frost@Sun.COM>2008-08-18 01:27:34 -0700
commite3d60c9bd991a9826cbfa63b10595d44e123b9c4 (patch)
tree6e65dbcfca9a620a015cd63ce7ee5feec803688b /usr/src
parentc8ec8eea9849cac239663c46be8a7f5d2ba7ca00 (diff)
downloadillumos-joyent-e3d60c9bd991a9826cbfa63b10595d44e123b9c4.tar.gz
PSARC 2008/527 FMA for Intel integrated memory controller and Nehalem CPUs
6706543 FMA for Intel Nehalem 6726376 generic machine check retires wrong virtual cpu 6695950 dimm fmri string contains garbage characters in x4450
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/devfsadm/i386/misc_link_i386.c5
-rw-r--r--usr/src/cmd/fm/dicts/GMCA.dict5
-rw-r--r--usr/src/cmd/fm/dicts/GMCA.po20
-rw-r--r--usr/src/cmd/fm/dicts/INTEL.dict9
-rw-r--r--usr/src/cmd/fm/dicts/INTEL.po114
-rw-r--r--usr/src/cmd/fm/eversholt/files/i386/i86pc/gcpu.esc55
-rw-r--r--usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc385
-rw-r--r--usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c6
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c3
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.c44
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_snap.c4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_subr.c32
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_subr.h4
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml5
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip.c207
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip.h6
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c92
-rw-r--r--usr/src/pkgdefs/SUNWcakr.i/prototype_com5
-rw-r--r--usr/src/uts/i86pc/Makefile.i86pc.shared3
-rw-r--r--usr/src/uts/i86pc/Makefile.rules7
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h28
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c7
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c232
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c66
-rw-r--r--usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c326
-rw-r--r--usr/src/uts/i86pc/intel_nhm/Makefile80
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/dimm_topo.c278
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/intel_nhm.c51
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/intel_nhm.conf28
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/intel_nhm.h221
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/intel_nhmdrv.c347
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/mem_addr.c913
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/nhm_init.c356
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/nhm_log.h85
-rw-r--r--usr/src/uts/i86pc/io/intel_nhm/nhm_pci_cfg.c159
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic.c80
-rw-r--r--usr/src/uts/i86pc/os/cmi.c49
-rw-r--r--usr/src/uts/i86pc/os/cmi_hw.c45
-rw-r--r--usr/src/uts/i86pc/os/mp_startup.c3
-rw-r--r--usr/src/uts/i86pc/os/startup.c5
-rw-r--r--usr/src/uts/i86pc/sys/apic.h3
-rw-r--r--usr/src/uts/i86pc/sys/cpu_module.h11
-rw-r--r--usr/src/uts/i86pc/sys/cpu_module_impl.h8
-rw-r--r--usr/src/uts/intel/ia32/ml/i86_subr.s12
-rw-r--r--usr/src/uts/intel/os/driver_aliases1
-rw-r--r--usr/src/uts/intel/sys/archsystm.h5
-rw-r--r--usr/src/uts/intel/sys/fm/cpu/GMCA.h15
-rw-r--r--usr/src/uts/intel/sys/mc_intel.h60
-rw-r--r--usr/src/uts/intel/sys/mca_x86.h66
50 files changed, 4274 insertions, 282 deletions
diff --git a/usr/src/cmd/devfsadm/i386/misc_link_i386.c b/usr/src/cmd/devfsadm/i386/misc_link_i386.c
index 808f603a56..c9eacc6fc4 100644
--- a/usr/src/cmd/devfsadm/i386/misc_link_i386.c
+++ b/usr/src/cmd/devfsadm/i386/misc_link_i386.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <regex.h>
#include <devfsadm.h>
#include <stdio.h>
@@ -567,7 +565,8 @@ mc_node(di_minor_t minor, di_node_t node)
(void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u",
unitaddr - MC_AMD_DEV_OFFSET);
} else {
- return (DEVFSADM_CONTINUE);
+ (void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u",
+ minor->dev_minor);
}
(void) devfsadm_mklink(linkpath, node, minor, 0);
return (DEVFSADM_CONTINUE);
diff --git a/usr/src/cmd/fm/dicts/GMCA.dict b/usr/src/cmd/fm/dicts/GMCA.dict
index ab5fdc1a46..4cb7b29ece 100644
--- a/usr/src/cmd/fm/dicts/GMCA.dict
+++ b/usr/src/cmd/fm/dicts/GMCA.dict
@@ -1,5 +1,5 @@
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -21,8 +21,6 @@
#
# CDDL HEADER END
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# DO NOT EDIT -- this file is generated by the Event Registry.
#
@@ -60,3 +58,4 @@ fault.memory.generic-x86.page_ce=29
fault.memory.generic-x86.page_ue=30
fault.memory.generic-x86.dimm_ce=31
fault.memory.generic-x86.dimm_ue=32
+fault.cpu.generic-x86.mc=33
diff --git a/usr/src/cmd/fm/dicts/GMCA.po b/usr/src/cmd/fm/dicts/GMCA.po
index a6e359d3c4..3d867e7659 100644
--- a/usr/src/cmd/fm/dicts/GMCA.po
+++ b/usr/src/cmd/fm/dicts/GMCA.po
@@ -1,5 +1,5 @@
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -21,8 +21,6 @@
#
# CDDL HEADER END
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# DO NOT EDIT -- this file is generated by the Event Registry.
#
#
@@ -537,3 +535,19 @@ msgid "GMCA-8001-09.impact"
msgstr "Retiring a single page from use will have negligible performance impact."
msgid "GMCA-8001-09.action"
msgstr "Schedule an urgent repair action to replace the memory module indicated by 'fmadm faulty'."
+#
+# code: GMCA-8001-1N
+# keys: fault.cpu.generic-x86.mc
+#
+msgid "GMCA-8001-1N.type"
+msgstr "Fault"
+msgid "GMCA-8001-1N.severity"
+msgstr "Major"
+msgid "GMCA-8001-1N.description"
+msgstr "Error detected in memory controller. Refer to %s for more information."
+msgid "GMCA-8001-1N.response"
+msgstr "Error detected in memory controller"
+msgid "GMCA-8001-1N.impact"
+msgstr "System may experience stability or performance problems"
+msgid "GMCA-8001-1N.action"
+msgstr "Investigate memory error. Use 'fmadm faulty' to identify FRU if one has been identified."
diff --git a/usr/src/cmd/fm/dicts/INTEL.dict b/usr/src/cmd/fm/dicts/INTEL.dict
index 4a188da541..434a0ce025 100644
--- a/usr/src/cmd/fm/dicts/INTEL.dict
+++ b/usr/src/cmd/fm/dicts/INTEL.dict
@@ -21,8 +21,6 @@
#
# CDDL HEADER END
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# DO NOT EDIT -- this file is generated by the Event Registry.
#
@@ -71,3 +69,10 @@ fault.memory.intel.page_ue=40
fault.memory.intel.dimm_ce=41
fault.memory.intel.dimm_ue=42
fault.cpu.intel.nb.otf=43
+fault.cpu.intel.quickpath.mem_parity=44
+fault.cpu.intel.quickpath.mem_addr_parity=45
+fault.cpu.intel.quickpath.mem_bad_addr=46
+fault.cpu.intel.quickpath.mem_spare=47
+fault.cpu.intel.quickpath.mem_bad_id=48
+fault.cpu.intel.quickpath.mem_redundant=49
+fault.cpu.intel.quickpath.interconnect=50
diff --git a/usr/src/cmd/fm/dicts/INTEL.po b/usr/src/cmd/fm/dicts/INTEL.po
index 63f0c5a8f5..70ac5740de 100644
--- a/usr/src/cmd/fm/dicts/INTEL.po
+++ b/usr/src/cmd/fm/dicts/INTEL.po
@@ -21,8 +21,6 @@
#
# CDDL HEADER END
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# DO NOT EDIT -- this file is generated by the Event Registry.
#
#
@@ -713,3 +711,115 @@ msgid "INTEL-8001-CC.impact"
msgstr "System may be unexpectedly reset"
msgid "INTEL-8001-CC.action"
msgstr "Supply more cooling"
+#
+# code: INTEL-8001-DJ
+# keys: fault.cpu.intel.quickpath.mem_parity
+#
+msgid "INTEL-8001-DJ.type"
+msgstr "Fault"
+msgid "INTEL-8001-DJ.severity"
+msgstr "Major"
+msgid "INTEL-8001-DJ.description"
+msgstr "Bad parity detected in memory write buffer or byte mask. Refer to %s for more information."
+msgid "INTEL-8001-DJ.response"
+msgstr "System panic or reset by BIOS"
+msgid "INTEL-8001-DJ.impact"
+msgstr "System may panic or be reset by BIOS"
+msgid "INTEL-8001-DJ.action"
+msgstr "Schedule a repair procedure to replace processor. Use 'fmadm faulty' to identify FRU."
+#
+# code: INTEL-8001-EE
+# keys: fault.cpu.intel.quickpath.mem_addr_parity
+#
+msgid "INTEL-8001-EE.type"
+msgstr "Fault"
+msgid "INTEL-8001-EE.severity"
+msgstr "Major"
+msgid "INTEL-8001-EE.description"
+msgstr "Bad parity detected in memory address within controller. Refer to %s for more information."
+msgid "INTEL-8001-EE.response"
+msgstr "System panic or reset by BIOS"
+msgid "INTEL-8001-EE.impact"
+msgstr "System may panic or be reset by BIOS"
+msgid "INTEL-8001-EE.action"
+msgstr "Schedule a repair procedure to replace processor. Use 'fmadm faulty' to identify FRU."
+#
+# code: INTEL-8001-FX
+# keys: fault.cpu.intel.quickpath.mem_bad_addr
+#
+msgid "INTEL-8001-FX.type"
+msgstr "Fault"
+msgid "INTEL-8001-FX.severity"
+msgstr "Major"
+msgid "INTEL-8001-FX.description"
+msgstr "Memory address is outside range mapped to memory dimms. Refer to %s for more information."
+msgid "INTEL-8001-FX.response"
+msgstr "System panic or reset by BIOS"
+msgid "INTEL-8001-FX.impact"
+msgstr "System may panic or be reset by BIOS"
+msgid "INTEL-8001-FX.action"
+msgstr "Schedule a repair procedure to replace processor. Use 'fmadm faulty' to identify FRU."
+#
+# code: INTEL-8001-G2
+# keys: fault.cpu.intel.quickpath.mem_spare
+#
+msgid "INTEL-8001-G2.type"
+msgstr "Fault"
+msgid "INTEL-8001-G2.severity"
+msgstr "Major"
+msgid "INTEL-8001-G2.description"
+msgstr "A fatal error occured while trying to deploy spare memory. Refer to %s for more information."
+msgid "INTEL-8001-G2.response"
+msgstr "System panic or reset by BIOS"
+msgid "INTEL-8001-G2.impact"
+msgstr "System may panic or be reset by BIOS"
+msgid "INTEL-8001-G2.action"
+msgstr "Replace faulty dimm. Use 'fmadm faulty' to identify the dimm."
+#
+# code: INTEL-8001-HS
+# keys: fault.cpu.intel.quickpath.mem_bad_id
+#
+msgid "INTEL-8001-HS.type"
+msgstr "Fault"
+msgid "INTEL-8001-HS.severity"
+msgstr "Major"
+msgid "INTEL-8001-HS.description"
+msgstr "Memory controller received bad transaction tracker ID from interconnect. Refer to %s for more information."
+msgid "INTEL-8001-HS.response"
+msgstr "System panic or reset by BIOS"
+msgid "INTEL-8001-HS.impact"
+msgstr "System may panic or be reset by BIOS"
+msgid "INTEL-8001-HS.action"
+msgstr "Schedule a repair procedure to replace processor. Use 'fmadm faulty' to identify FRU."
+#
+# code: INTEL-8001-J5
+# keys: fault.cpu.intel.quickpath.mem_redundant
+#
+msgid "INTEL-8001-J5.type"
+msgstr "Fault"
+msgid "INTEL-8001-J5.severity"
+msgstr "Minor"
+msgid "INTEL-8001-J5.description"
+msgstr "Memory Mirroring lost due to error. Refer to %s for more information."
+msgid "INTEL-8001-J5.response"
+msgstr "There is no spare copy of memory"
+msgid "INTEL-8001-J5.impact"
+msgstr "There is a loss of hardware redundancy"
+msgid "INTEL-8001-J5.action"
+msgstr "Replace faulty dimm. Use 'fmadm faulty' to identify the dimm."
+#
+# code: INTEL-8001-KP
+# keys: fault.cpu.intel.quickpath.interconnect
+#
+msgid "INTEL-8001-KP.type"
+msgstr "Fault"
+msgid "INTEL-8001-KP.severity"
+msgstr "Major"
+msgid "INTEL-8001-KP.description"
+msgstr "Quickpath Deteced Error. Refer to %s for more information."
+msgid "INTEL-8001-KP.response"
+msgstr "System panic or reset by BIOS"
+msgid "INTEL-8001-KP.impact"
+msgstr "System may panic or be reset by BIOS"
+msgid "INTEL-8001-KP.action"
+msgstr "Schedule a repair procedure to check seating of proccessors"
diff --git a/usr/src/cmd/fm/eversholt/files/i386/i86pc/gcpu.esc b/usr/src/cmd/fm/eversholt/files/i386/i86pc/gcpu.esc
index 8ea5add988..c69196c738 100644
--- a/usr/src/cmd/fm/eversholt/files/i386/i86pc/gcpu.esc
+++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/gcpu.esc
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* eversholt rules for generic x86 MCA
*
@@ -43,7 +41,8 @@
*/
#define SMPL_EVENT(leafclass) \
- event ereport.cpu.generic-x86.leafclass@chip/cpu { within(1s) }
+ event ereport.cpu.generic-x86.leafclass@chip/cpu { within(1s) }; \
+ event ereport.cpu.generic-x86.leafclass@chip/core/strand { within(1s) }
SMPL_EVENT(unknown);
SMPL_EVENT(unclassified);
@@ -51,6 +50,7 @@ SMPL_EVENT(microcode_rom_parity);
SMPL_EVENT(external);
SMPL_EVENT(frc);
SMPL_EVENT(internal_timer);
+SMPL_EVENT(internal_parity);
SMPL_EVENT(internal_unclassified);
/*
@@ -64,25 +64,42 @@ SMPL_EVENT(internal_unclassified);
engine serd.cpu.generic-x86.simple@chip/cpu, N=SMPL_N, T=72h;
event fault.cpu.generic-x86.internal@chip/cpu,
engine=serd.cpu.generic-x86.simple@chip/cpu;
+engine serd.cpu.generic-x86.simple@chip/core/strand, N=SMPL_N, T=72h;
+event fault.cpu.generic-x86.internal@chip/core/strand,
+ engine=serd.cpu.generic-x86.simple@chip/core/strand;
prop fault.cpu.generic-x86.internal@chip/cpu
{ payloadprop("error_uncorrected") == 1 ?
setserdincrement(SMPL_N + 1) : 1 } (1)->
ereport.cpu.generic-x86.microcode_rom_parity@chip/cpu,
ereport.cpu.generic-x86.internal_timer@chip/cpu,
+ ereport.cpu.generic-x86.internal_parity@chip/cpu,
ereport.cpu.generic-x86.unclassified@chip/cpu,
ereport.cpu.generic-x86.internal_unclassified@chip/cpu,
ereport.cpu.generic-x86.frc@chip/cpu;
+prop fault.cpu.generic-x86.internal@chip/core/strand
+ { payloadprop("error_uncorrected") == 1 ?
+ setserdincrement(SMPL_N + 1) : 1 } (1)->
+ ereport.cpu.generic-x86.microcode_rom_parity@chip/core/strand,
+ ereport.cpu.generic-x86.internal_timer@chip/core/strand,
+ ereport.cpu.generic-x86.internal_parity@chip/core/strand,
+ ereport.cpu.generic-x86.unclassified@chip/core/strand,
+ ereport.cpu.generic-x86.internal_unclassified@chip/core/strand,
+ ereport.cpu.generic-x86.frc@chip/core/strand;
/*
* Ereports for Compound error codes. These are in pairs "foo" and "foo_uc"
* for the corrected and uncorrected version of each error type. All are
- * detected at chip/cpu.
+ * detected at chip/cpu and chip/core/strand.
*/
#define CMPND_EVENT(leafclass) \
event ereport.cpu.generic-x86.leafclass@chip/cpu { within(1s) }; \
- event ereport.cpu.generic-x86.leafclass/**/_uc@chip/cpu { within(1s) }
+ event ereport.cpu.generic-x86.leafclass/**/_uc@chip/cpu { within(1s) };\
+ event ereport.cpu.generic-x86.leafclass@chip/core/strand \
+ { within(1s) }; \
+ event ereport.cpu.generic-x86.leafclass/**/_uc@chip/core/strand \
+ { within(1s) }
/*
* Ereports for Compound error codes - generic memory hierarchy errors
@@ -129,6 +146,7 @@ CMPND_EVENT(icache);
CMPND_EVENT(bus_interconnect);
CMPND_EVENT(bus_interconnect_memory);
CMPND_EVENT(bus_interconnect_io);
+CMPND_EVENT(mc);
/*
* Compound error propogations
@@ -147,23 +165,39 @@ CMPND_EVENT(bus_interconnect_io);
engine serd.cpu.generic-x86.fltleaf@chip/cpu, N=n, T=t; \
event fault.cpu.generic-x86.fltleaf@chip/cpu, \
engine=serd.cpu.generic-x86.fltleaf@chip/cpu; \
+ engine serd.cpu.generic-x86.fltleaf@chip/core/strand, N=n, T=t; \
+ event fault.cpu.generic-x86.fltleaf@chip/core/strand, \
+ engine=serd.cpu.generic-x86.fltleaf@chip/core/strand; \
\
prop fault.cpu.generic-x86.fltleaf@chip/cpu (0)-> \
ereport.cpu.generic-x86.erptleaf@chip/cpu; \
prop fault.cpu.generic-x86.fltleaf@chip/cpu \
{ setserdincrement(n + 1) } (0)-> \
- ereport.cpu.generic-x86.erptleaf/**/_uc@chip/cpu
+ ereport.cpu.generic-x86.erptleaf/**/_uc@chip/cpu; \
+ prop fault.cpu.generic-x86.fltleaf@chip/core/strand (0)-> \
+ ereport.cpu.generic-x86.erptleaf@chip/core/strand; \
+ prop fault.cpu.generic-x86.fltleaf@chip/core/strand \
+ { setserdincrement(n + 1) } (0)-> \
+ ereport.cpu.generic-x86.erptleaf/**/_uc@chip/core/strand
#define CMPND_FLT_PROP_2(erptleaf, fltleaf, n, t) \
engine serd.cpu.generic-x86.fltleaf@chip/cpu, N=n, T=t; \
event fault.cpu.generic-x86.fltleaf@chip/cpu, retire=0, \
response=0, engine=serd.cpu.generic-x86.fltleaf@chip/cpu; \
+ engine serd.cpu.generic-x86.fltleaf@chip/core/strand, N=n, T=t; \
+ event fault.cpu.generic-x86.fltleaf@chip/core/strand, retire=0, \
+ response=0, engine=serd.cpu.generic-x86.fltleaf@chip/core/strand;\
\
prop fault.cpu.generic-x86.fltleaf@chip/cpu (0)-> \
ereport.cpu.generic-x86.erptleaf@chip/cpu; \
prop fault.cpu.generic-x86.fltleaf@chip/cpu \
{ setserdincrement(n + 1) } (0)-> \
- ereport.cpu.generic-x86.erptleaf/**/_uc@chip/cpu
+ ereport.cpu.generic-x86.erptleaf/**/_uc@chip/cpu; \
+ prop fault.cpu.generic-x86.fltleaf@chip/core/strand (0)-> \
+ ereport.cpu.generic-x86.erptleaf@chip/core/strand; \
+ prop fault.cpu.generic-x86.fltleaf@chip/core/strand \
+ { setserdincrement(n + 1) } (0)-> \
+ ereport.cpu.generic-x86.erptleaf/**/_uc@chip/core/strand
CMPND_FLT_PROP_1(l0cache, l0cache, 3, 72h);
CMPND_FLT_PROP_1(l1cache, l1cache, 3, 72h);
@@ -199,6 +233,8 @@ CMPND_FLT_PROP_2(bus_interconnect, bus_interconnect, 10, 72h);
CMPND_FLT_PROP_2(bus_interconnect_memory, bus_interconnect_memory, 10, 72h);
CMPND_FLT_PROP_2(bus_interconnect_io, bus_interconnect_io, 10, 72h);
+CMPND_FLT_PROP_2(mc, mc, 10, 72h);
+
/*
* Discards - not enough info to diagnose.
*/
@@ -208,3 +244,8 @@ prop upset.discard@chip/cpu (0)->
ereport.cpu.generic-x86.external@chip/cpu,
ereport.cpu.generic-x86.unknown@chip/cpu;
+event upset.discard@chip/core/strand;
+
+prop upset.discard@chip/core/strand (0)->
+ ereport.cpu.generic-x86.external@chip/core/strand,
+ ereport.cpu.generic-x86.unknown@chip/core/strand;
diff --git a/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc b/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc
index 20bd5556ce..b535c0924c 100644
--- a/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc
+++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#pragma dictionary "INTEL"
/*
@@ -37,7 +35,8 @@
*/
#define SMPL_EVENT(leafclass, t) \
- event ereport.cpu.intel.leafclass@chip/cpu { within(t) }
+ event ereport.cpu.intel.leafclass@chip/cpu { within(t) }; \
+ event ereport.cpu.intel.leafclass@chip/core/strand { within(t) }
SMPL_EVENT(unknown, 1s);
SMPL_EVENT(unclassified, 1s);
@@ -45,6 +44,7 @@ SMPL_EVENT(microcode_rom_parity, 1s);
SMPL_EVENT(external, 1s);
SMPL_EVENT(frc, 1s);
SMPL_EVENT(internal_timer, 1s);
+SMPL_EVENT(internal_parity, 1s);
SMPL_EVENT(internal_unclassified, 1s);
/*
@@ -56,24 +56,38 @@ SMPL_EVENT(internal_unclassified, 1s);
engine serd.cpu.intel.simple@chip/cpu, N=3, T=72h;
event fault.cpu.intel.internal@chip/cpu, engine=serd.cpu.intel.simple@chip/cpu;
+engine serd.cpu.intel.simple@chip/core/strand, N=3, T=72h;
+event fault.cpu.intel.internal@chip/core/strand,
+ engine=serd.cpu.intel.simple@chip/core/strand;
prop fault.cpu.intel.internal@chip/cpu
{ payloadprop("error_uncorrected") == 1 ? setserdincrement(4) : 1} (0)->
ereport.cpu.intel.microcode_rom_parity@chip/cpu,
ereport.cpu.intel.internal_timer@chip/cpu,
+ ereport.cpu.intel.internal_parity@chip/cpu,
ereport.cpu.intel.unclassified@chip/cpu,
ereport.cpu.intel.internal_unclassified@chip/cpu,
ereport.cpu.intel.frc@chip/cpu;
+prop fault.cpu.intel.internal@chip/core/strand
+ { payloadprop("error_uncorrected") == 1 ? setserdincrement(4) : 1} (0)->
+ ereport.cpu.intel.microcode_rom_parity@chip/core/strand,
+ ereport.cpu.intel.internal_timer@chip/core/strand,
+ ereport.cpu.intel.internal_parity@chip/core/strand,
+ ereport.cpu.intel.unclassified@chip/core/strand,
+ ereport.cpu.intel.internal_unclassified@chip/core/strand,
+ ereport.cpu.intel.frc@chip/core/strand;
/*
* Ereports for Compound error codes. These are in pairs "foo" and "foo_uc"
* for the corrected and uncorrected version of each error type. All are
- * detected at chip/cpu.
+ * detected at chip/cpu and chip/core/strand.
*/
#define CMPND_EVENT(leafclass, t) \
event ereport.cpu.intel.leafclass@chip/cpu { within(t) }; \
- event ereport.cpu.intel.leafclass/**/_uc@chip/cpu { within(t) }
+ event ereport.cpu.intel.leafclass/**/_uc@chip/cpu { within(t) }; \
+ event ereport.cpu.intel.leafclass@chip/core/strand { within(t) }; \
+ event ereport.cpu.intel.leafclass/**/_uc@chip/core/strand { within(t) }
/*
* Ereports for Compound error codes - intel errors
@@ -138,25 +152,41 @@ CMPND_EVENT(bus_interconnect_io, 1s);
engine serd.cpu.intel.fltleaf@chip/cpu, N=n, T=t; \
event fault.cpu.intel.fltleaf@chip/cpu, \
engine=serd.cpu.intel.fltleaf@chip/cpu; \
+ engine serd.cpu.intel.fltleaf@chip/core/strand, N=n, T=t; \
+ event fault.cpu.intel.fltleaf@chip/core/strand, \
+ engine=serd.cpu.intel.fltleaf@chip/core/strand; \
\
prop fault.cpu.intel.fltleaf@chip/cpu (0)-> \
ereport.cpu.intel.erptleaf@chip/cpu; \
+ prop fault.cpu.intel.fltleaf@chip/core/strand (0)-> \
+ ereport.cpu.intel.erptleaf@chip/core/strand; \
\
prop fault.cpu.intel.fltleaf@chip/cpu \
{ setserdincrement(n + 1) } (0)-> \
- ereport.cpu.intel.erptleaf/**/_uc@chip/cpu
+ ereport.cpu.intel.erptleaf/**/_uc@chip/cpu; \
+ prop fault.cpu.intel.fltleaf@chip/core/strand \
+ { setserdincrement(n + 1) } (0)-> \
+ ereport.cpu.intel.erptleaf/**/_uc@chip/core/strand
#define CMPND_FLT_PROP_2(erptleaf, fltleaf, n, t) \
engine serd.cpu.intel.fltleaf@chip/cpu, N=n, T=t; \
event fault.cpu.intel.fltleaf@chip/cpu, retire=0, response=0, \
engine=serd.cpu.intel.fltleaf@chip/cpu; \
+ engine serd.cpu.intel.fltleaf@chip/core/strand, N=n, T=t; \
+ event fault.cpu.intel.fltleaf@chip/core/strand, retire=0, response=0,\
+ engine=serd.cpu.intel.fltleaf@chip/core/strand; \
\
prop fault.cpu.intel.fltleaf@chip/cpu (0)-> \
ereport.cpu.intel.erptleaf@chip/cpu; \
+ prop fault.cpu.intel.fltleaf@chip/core/strand (0)-> \
+ ereport.cpu.intel.erptleaf@chip/core/strand; \
\
prop fault.cpu.intel.fltleaf@chip/cpu \
{ setserdincrement(n + 1) } (0)-> \
- ereport.cpu.intel.erptleaf/**/_uc@chip/cpu
+ ereport.cpu.intel.erptleaf/**/_uc@chip/cpu; \
+ prop fault.cpu.intel.fltleaf@chip/core/strand \
+ { setserdincrement(n + 1) } (0)-> \
+ ereport.cpu.intel.erptleaf/**/_uc@chip/core/strand
CMPND_FLT_PROP_1(l0cache, l0cache, 3, 72h);
CMPND_FLT_PROP_1(l1cache, l1cache, 3, 72h);
@@ -198,6 +228,12 @@ prop upset.discard@chip/cpu (0)->
ereport.cpu.intel.external@chip/cpu,
ereport.cpu.intel.unknown@chip/cpu;
+event upset.discard@chip/core/strand;
+
+prop upset.discard@chip/core/strand (0)->
+ ereport.cpu.intel.external@chip/core/strand,
+ ereport.cpu.intel.unknown@chip/core/strand;
+
/* errors detected in northbridge */
@@ -212,63 +248,69 @@ prop upset.discard@chip/cpu (0)->
#define SET_OFFSET (!payloadprop_defined("offset") || \
setpayloadprop("asru-offset", payloadprop("offset")))
+#define EREPORT_BUS_ERROR \
+ ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu, \
+ ereport.cpu.intel.bus_interconnect_uc@chip/cpu, \
+ ereport.cpu.intel.bus_interconnect_memory@chip/cpu, \
+ ereport.cpu.intel.bus_interconnect@chip/cpu, \
+ ereport.cpu.intel.external@chip/cpu, \
+ ereport.cpu.intel.bus_interconnect_memory_uc@chip/core/strand, \
+ ereport.cpu.intel.bus_interconnect_uc@chip/core/strand, \
+ ereport.cpu.intel.bus_interconnect_memory@chip/core/strand, \
+ ereport.cpu.intel.bus_interconnect@chip/core/strand, \
+ ereport.cpu.intel.external@chip/core/strand
+
engine stat.ce_pgflt@memory-controller/dram-channel/dimm;
-event ereport.cpu.intel.nb.mem_ue@memory-controller{within(12s)};
-event ereport.cpu.intel.nb.fbd.ma@memory-controller{within(12s)};
-event fault.memory.intel.page_ue@memory-controller/dram-channel/dimm/rank,
+event ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller{within(12s)};
+event ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller{within(12s)};
+event fault.memory.intel.page_ue@
+ motherboard/memory-controller/dram-channel/dimm/rank,
message=0, response=0;
-event fault.memory.intel.dimm_ue@memory-controller/dram-channel/dimm/rank;
+event fault.memory.intel.dimm_ue@
+ motherboard/memory-controller/dram-channel/dimm/rank;
prop fault.memory.intel.page_ue@
- memory-controller/dram-channel/dimm/rank[rank_num]
+ motherboard/memory-controller/dram-channel/dimm/rank[rank_num]
{ payloadprop_defined("rank") && rank_num == payloadprop("rank") &&
(payloadprop_defined("physaddr") || payloadprop_defined("offset")) &&
SET_ADDR && SET_OFFSET } (1)->
- ereport.cpu.intel.nb.mem_ue@memory-controller,
- ereport.cpu.intel.nb.fbd.ma@memory-controller;
+ ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+ ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
-prop fault.memory.intel.page_ue@memory-controller/dram-channel/dimm/rank (1)->
- ereport.cpu.intel.nb.mem_ue@memory-controller,
- ereport.cpu.intel.nb.fbd.ma@memory-controller;
+prop fault.memory.intel.page_ue@
+ motherboard/memory-controller/dram-channel/dimm/rank (1)->
+ ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+ ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
-prop fault.memory.intel.page_ue@memory-controller/dram-channel/dimm/rank (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop fault.memory.intel.page_ue@
+ motherboard/memory-controller/dram-channel/dimm/rank (0)->
+ EREPORT_BUS_ERROR;
prop fault.memory.intel.dimm_ue@
- memory-controller/dram-channel<channel_num>/dimm/rank[rank_num]
+ motherboard/memory-controller/dram-channel<channel_num>/dimm/rank[rank_num]
{ payloadprop_defined("rank") && rank_num == payloadprop("rank") } (1)->
- ereport.cpu.intel.nb.mem_ue@memory-controller,
- ereport.cpu.intel.nb.fbd.ma@memory-controller;
+ ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+ ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
-prop fault.memory.intel.dimm_ue@memory-controller/dram-channel/dimm/rank (1)->
- ereport.cpu.intel.nb.mem_ue@memory-controller,
- ereport.cpu.intel.nb.fbd.ma@memory-controller;
+prop fault.memory.intel.dimm_ue@
+ motherboard/memory-controller/dram-channel/dimm/rank (1)->
+ ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+ ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
-prop fault.memory.intel.dimm_ue@memory-controller/dram-channel/dimm/rank (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop fault.memory.intel.dimm_ue@
+ motherboard/memory-controller/dram-channel/dimm/rank (0)->
+ EREPORT_BUS_ERROR;
-event upset.memory.intel.discard@memory-controller{within(1s)};
+event upset.memory.intel.discard@motherboard/memory-controller{within(1s)};
-prop upset.memory.intel.discard@memory-controller
+prop upset.memory.intel.discard@motherboard/memory-controller
{ !payloadprop_defined("rank") } (1)->
- ereport.cpu.intel.nb.mem_ue@memory-controller,
- ereport.cpu.intel.nb.fbd.ma@memory-controller;
+ ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+ ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
-prop upset.memory.intel.discard@memory-controller (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop upset.memory.intel.discard@motherboard/memory-controller (0)->
+ EREPORT_BUS_ERROR;
#define PAGE_CE_COUNT 2
#define PAGE_CE_TIME 72h
@@ -323,11 +365,7 @@ prop fault.memory.intel.fbd.alert@rank (1)->
ereport.cpu.intel.nb.fbd.alert@rank;
prop fault.memory.intel.fbd.alert@rank (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+ EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.fbd.crc@rank{within(12s)};
event fault.memory.intel.fbd.crc@rank, retire=0;
@@ -335,12 +373,7 @@ event fault.memory.intel.fbd.crc@rank, retire=0;
prop fault.memory.intel.fbd.crc@rank (1)->
ereport.cpu.intel.nb.fbd.crc@rank;
-prop fault.memory.intel.fbd.crc@rank (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop fault.memory.intel.fbd.crc@rank (0)-> EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.fbd.reset_timeout@memory-controller {within(12s)};
event fault.memory.intel.fbd.reset_timeout@memory-controller, retire=0;
@@ -349,11 +382,7 @@ prop fault.memory.intel.fbd.reset_timeout@memory-controller (1)->
ereport.cpu.intel.nb.fbd.reset_timeout@memory-controller;
prop fault.memory.intel.fbd.reset_timeout@memory-controller (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+ EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.fbd.ch@dram-channel {within(12s)};
engine serd.cpu.intel.nb.fbd.ch@dram-channel, N=2, T=1month;
@@ -364,11 +393,7 @@ prop fault.memory.intel.fbd.ch@dram-channel (1)->
ereport.cpu.intel.nb.fbd.ch@dram-channel;
prop fault.memory.intel.fbd.ch@dram-channel (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+ EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.fbd.otf@dram-channel {within(12s)};
engine serd.cpu.intel.nb.fbd_otf@dram-channel, N=2, T=1week;
@@ -409,12 +434,7 @@ event fault.cpu.intel.nb.fsb@chip, retire=0;
prop fault.cpu.intel.nb.fsb@chip (1)->
ereport.cpu.intel.nb.fsb@chip;
-prop fault.cpu.intel.nb.fsb@chip (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop fault.cpu.intel.nb.fsb@chip (0)-> EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.ie@motherboard{within(12s)};
event fault.cpu.intel.nb.ie@motherboard, retire=0;
@@ -422,12 +442,7 @@ event fault.cpu.intel.nb.ie@motherboard, retire=0;
prop fault.cpu.intel.nb.ie@motherboard (1)->
ereport.cpu.intel.nb.ie@motherboard;
-prop fault.cpu.intel.nb.ie@motherboard (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop fault.cpu.intel.nb.ie@motherboard (0)-> EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.dma@motherboard{within(12s)};
event fault.cpu.intel.nb.dma@motherboard, retire=0, response=0;
@@ -435,12 +450,7 @@ event fault.cpu.intel.nb.dma@motherboard, retire=0, response=0;
prop fault.cpu.intel.nb.dma@motherboard (1)->
ereport.cpu.intel.nb.dma@motherboard;
-prop fault.cpu.intel.nb.dma@motherboard (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop fault.cpu.intel.nb.dma@motherboard (0)-> EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.esi@motherboard{within(12s)};
event ereport.cpu.intel.nb.pex@hostbridge{within(12s)};
@@ -450,12 +460,7 @@ prop upset.cpu.intel.nb.pex@hostbridge (1)->
ereport.cpu.intel.nb.esi@motherboard,
ereport.cpu.intel.nb.pex@hostbridge;
-prop upset.cpu.intel.nb.pex@hostbridge (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop upset.cpu.intel.nb.pex@hostbridge (0)-> EREPORT_BUS_ERROR;
event ereport.cpu.intel.nb.unknown@rank{within(12s)};
event upset.discard@rank;
@@ -463,9 +468,197 @@ event upset.discard@rank;
prop upset.discard@rank (1)->
ereport.cpu.intel.nb.unknown@rank;
-prop upset.discard@rank (0)->
- ereport.cpu.intel.bus_interconnect_memory_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_uc@chip/cpu,
- ereport.cpu.intel.bus_interconnect_memory@chip/cpu,
- ereport.cpu.intel.bus_interconnect@chip/cpu,
- ereport.cpu.intel.external@chip/cpu;
+prop upset.discard@rank (0)-> EREPORT_BUS_ERROR;
+
+/*
+ * CPU integrated memory controller
+ */
+
+#define CONTAINS_RANK (payloadprop_contains("resource", \
+ asru(motherboard/chip/memory-controller/dram-channel/dimm/rank)) || \
+ payloadprop_contains("resource", \
+ asru(motherboard/chip/memory-controller/dram-channel/dimm)))
+
+#define CPU_MEM_CE_PGFLTS \
+ (count(stat.ce_pgflt@motherboard/chip/memory-controller/dram-channel/dimm))
+
+engine stat.ce_pgflt@motherboard/chip/memory-controller/dram-channel/dimm;
+
+event ereport.cpu.intel.quickpath.mem_ue@motherboard/chip/memory-controller
+ {within(12s)};
+
+event fault.memory.intel.page_ue@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank,
+ message=0, response=0; /* do not message individual pageflts */
+
+prop fault.memory.intel.page_ue@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank
+ { CONTAINS_RANK &&
+ (payloadprop_defined("physaddr") || payloadprop_defined("offset")) &&
+ SET_ADDR && SET_OFFSET } (1)->
+ ereport.cpu.intel.quickpath.mem_ue@motherboard/chip/memory-controller;
+
+event fault.memory.intel.dimm_ue@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank;
+
+prop fault.memory.intel.dimm_ue@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank
+ { CONTAINS_RANK } (1)->
+ ereport.cpu.intel.quickpath.mem_ue@motherboard/chip/memory-controller;
+
+prop fault.memory.intel.dimm_ue@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank (0)->
+ EREPORT_BUS_ERROR;
+
+event ereport.cpu.intel.quickpath.mem_ce@
+ motherboard/chip/memory-controller{within(12s)};
+
+engine serd.memory.intel.page_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank,
+ N=PAGE_CE_COUNT, T=PAGE_CE_TIME;
+
+event fault.memory.intel.page_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank,
+ message=0, response=0,
+ count=stat.ce_pgflt@motherboard/chip/memory-controller/dram-channel/dimm,
+ engine=serd.memory.intel.page_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank;
+
+prop fault.memory.intel.page_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank
+ { CONTAINS_RANK &&
+ (payloadprop_defined("physaddr") || payloadprop_defined("offset")) &&
+ SET_ADDR && SET_OFFSET } (1)->
+ ereport.cpu.intel.quickpath.mem_ce@motherboard/chip/memory-controller;
+
+engine serd.memory.intel.dimm_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm,
+ N=PAGE_CE_COUNT, T=PAGE_CE_TIME;
+event fault.memory.intel.dimm_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm,
+ engine=serd.memory.intel.dimm_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm;
+event error.memory.intel.dimm_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm;
+prop fault.memory.intel.dimm_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm
+ { !confprop_defined(dimm, "dimm-size") } (1)->
+ error.memory.intel.dimm_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm;
+prop error.memory.intel.dimm_ce@
+ motherboard/chip/memory-controller/dram-channel/dimm
+ { !confprop_defined(dimm, "dimm-size") &&
+ count(stat.ce_pgflt@dimm) > 512 } (1)->
+ ereport.cpu.intel.quickpath.mem_ce@motherboard/chip/memory-controller;
+
+#define CPU_MEM_DIMM_CE(dimm_size, n, t, fault_rate) \
+ prop fault.memory.intel.dimm_ce@ \
+ motherboard/chip/memory-controller/dram-channel/dimm { \
+ confprop(dimm, "dimm-size") == dimm_size && \
+ setserdn(n) & setserdt(t) } (1)-> \
+ error.memory.intel.dimm_ce@ \
+ motherboard/chip/memory-controller/dram-channel/dimm; \
+ prop error.memory.intel.dimm_ce@ \
+ motherboard/chip/memory-controller/dram-channel/dimm { \
+ confprop(dimm, "dimm-size") == dimm_size && \
+ count(stat.ce_pgflt@dimm) > fault_rate } (1)-> \
+ ereport.cpu.intel.quickpath.mem_ce@ \
+ motherboard/chip/memory-controller;
+
+CPU_MEM_DIMM_CE("16G", 16, 1week, 2000)
+CPU_MEM_DIMM_CE("8G", 8, 1week, 2000)
+CPU_MEM_DIMM_CE("4G", 4, 1week, 1500)
+CPU_MEM_DIMM_CE("2G", 4, 2week, 1000)
+CPU_MEM_DIMM_CE("1G", 4, 4week, 500)
+CPU_MEM_DIMM_CE("512M", 4, 8week, 250)
+
+event ereport.cpu.intel.quickpath.mem_unknown@motherboard/chip/memory-controller {within(12s)};
+event ereport.cpu.intel.quickpath.mem_unknown@motherboard/chip/memory-controller/dram-channel
+ {within(12s)};
+event ereport.cpu.intel.quickpath.mem_unknown@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank{within(12s)};
+event upset.discard@motherboard/chip/memory-controller;
+event upset.discard@motherboard/chip/memory-controller/dram-channel/dimm/rank;
+
+prop upset.discard@motherboard/chip/memory-controller (0)->
+ ereport.cpu.intel.quickpath.mem_unknown@motherboard/chip/memory-controller,
+ ereport.cpu.intel.quickpath.mem_unknown@
+ motherboard/chip/memory-controller/dram-channel;
+
+prop upset.discard@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank (1)->
+ ereport.cpu.intel.quickpath.mem_unknown@
+ motherboard/chip/memory-controller/dram-channel/dimm/rank;
+
+event ereport.cpu.intel.quickpath.mem_parity@motherboard/chip/memory-controller {within(1s)};
+event fault.cpu.intel.quickpath.mem_parity@motherboard/chip/memory-controller;
+
+prop fault.cpu.intel.quickpath.mem_parity@motherboard/chip/memory-controller (1)->
+ ereport.cpu.intel.quickpath.mem_parity@motherboard/chip/memory-controller;
+
+event ereport.cpu.intel.quickpath.mem_addr_parity@motherboard/chip/memory-controller {within(1s)};
+event fault.cpu.intel.quickpath.mem_addr_parity@
+ motherboard/chip/memory-controller/dram-channel/dimm;
+event fault.cpu.intel.quickpath.mem_addr_parity@
+ motherboard/chip/memory-controller;
+
+prop fault.cpu.intel.quickpath.mem_addr_parity@
+ motherboard/chip/memory-controller (1)->
+ ereport.cpu.intel.quickpath.mem_addr_parity@motherboard/chip/memory-controller;
+
+prop fault.cpu.intel.quickpath.mem_addr_parity@
+ motherboard/chip/memory-controller/dram-channel/dimm
+ { payloadprop_contains("resource", asru(motherboard/chip/memory-controller/dram-channel/dimm)) } (1)->
+ ereport.cpu.intel.quickpath.mem_addr_parity@motherboard/chip/memory-controller;
+
+event ereport.cpu.intel.quickpath.mem_bad_addr@motherboard/chip/memory-controller {within(1s)};
+event fault.cpu.intel.quickpath.mem_bad_addr@motherboard/chip/memory-controller;
+
+prop fault.cpu.intel.quickpath.mem_bad_addr@motherboard/chip/memory-controller (1)->
+ ereport.cpu.intel.quickpath.mem_bad_addr@motherboard/chip/memory-controller;
+
+event ereport.cpu.intel.quickpath.mem_spare@motherboard/chip/memory-controller {within(1s)};
+event fault.cpu.intel.quickpath.mem_spare@
+ motherboard/chip/memory-controller/dram-channel/dimm;
+
+prop fault.cpu.intel.quickpath.mem_spare@
+ motherboard/chip/memory-controller/dram-channel/dimm (1)->
+ ereport.cpu.intel.quickpath.mem_spare@motherboard/chip/memory-controller;
+
+event ereport.cpu.intel.quickpath.mem_bad_id@motherboard/chip/memory-controller {within(1s)};
+event fault.cpu.intel.quickpath.mem_bad_id@motherboard/chip/memory-controller;
+
+prop fault.cpu.intel.quickpath.mem_bad_id@motherboard/chip/memory-controller (1)->
+ ereport.cpu.intel.quickpath.mem_bad_id@motherboard/chip/memory-controller;
+
+event ereport.cpu.intel.quickpath.mem_redundant@motherboard/chip/memory-controller {within(1s)};
+engine serd.cpu.intel.quickpath.mem_redundant@motherboard/chip/memory-controller,
+ N=2, T=72h;
+event fault.cpu.intel.quickpath.mem_redundant@
+ motherboard/chip/memory-controller/dram-channel/dimm,
+ engine=serd.cpu.intel.quickpath.mem_redundant@
+ motherboard/chip/memory-controller;
+
+prop fault.cpu.intel.quickpath.mem_redundant@
+ motherboard/chip/memory-controller/dram-channel/dimm (1)->
+ ereport.cpu.intel.quickpath.mem_redundant@
+ motherboard/chip/memory-controller;
+
+event ereport.cpu.intel.quickpath.interconnect@motherboard/chip
+ {within(1s)};
+event upset.cpu.intel.quickpath.interconnect@motherboard/chip;
+/* Diagnose corrected events to upsets */
+prop upset.cpu.intel.quickpath.interconnect@motherboard/chip
+ { !STATUS_UC } (1)->
+ ereport.cpu.intel.quickpath.interconnect@motherboard/chip;
+
+
+engine serd.cpu.intel.quickpath.interconnect@motherboard/chip,
+ N=3, T=72h;
+event fault.cpu.intel.quickpath.interconnect@motherboard/chip,
+ engine=serd.cpu.intel.quickpath.interconnect@motherboard/chip;
+
+/* Diagnose uncorrected events to faults */
+prop fault.cpu.intel.quickpath.interconnect@motherboard/chip
+ { STATUS_UC } (0)->
+ ereport.cpu.intel.quickpath.interconnect@motherboard/chip;
diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c
index eb9ac7c158..75f3452c61 100644
--- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c
+++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <cma.h>
#include <strings.h>
@@ -220,6 +218,10 @@ static const cma_subscriber_t cma_subrs[] = {
FM_CPU_SCHEME_VERSION, NULL },
{ "fault.cpu.intel.nb.*", FM_FMRI_SCHEME_HC,
FM_HC_SCHEME_VERSION, NULL },
+ { "fault.cpu.intel.quickpath.*", FM_FMRI_SCHEME_HC,
+ FM_HC_SCHEME_VERSION, NULL },
+ { "fault.cpu.generic-x86.mc", FM_FMRI_SCHEME_HC,
+ FM_HC_SCHEME_VERSION, NULL },
{ "fault.cpu.intel.dma", FM_FMRI_SCHEME_HC,
FM_HC_SCHEME_VERSION, NULL },
{ "fault.cpu.intel.dma", FM_FMRI_SCHEME_CPU,
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c
index 8b9c8f08a8..15b9e60608 100644
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c
@@ -25,8 +25,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -129,6 +127,7 @@ static const hcc_t hc_canon[] = {
{ CHIP, TOPO_STABILITY_PRIVATE },
{ CHIP_SELECT, TOPO_STABILITY_PRIVATE },
{ CORE, TOPO_STABILITY_PRIVATE },
+ { STRAND, TOPO_STABILITY_PRIVATE },
{ CONTROLLER, TOPO_STABILITY_PRIVATE },
{ CPU, TOPO_STABILITY_PRIVATE },
{ CPUBOARD, TOPO_STABILITY_PRIVATE },
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
index 797f251cb3..36dabb4c3f 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -27,8 +27,6 @@
#ifndef _TOPO_HC_H
#define _TOPO_HC_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -44,8 +42,9 @@ extern "C" {
#define CENTERPLANE "centerplane"
#define CHASSIS "chassis"
#define CHIP "chip"
-#define CHIP_SELECT "chip-select"
#define CORE "core"
+#define STRAND "strand"
+#define CHIP_SELECT "chip-select"
#define CONTROLLER "controller"
#define CPU "cpu"
#define CPUBOARD "cpuboard"
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
index 4140fc0ed2..1f47b963c8 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Topology Plugin Modules
*
@@ -296,6 +294,7 @@ topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
int err;
nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL;
nvlist_t *nfp = NULL;
+ char *lpart, *lrev, *lserial;
if (version != FM_HC_SCHEME_VERSION)
return (set_fmri_err(mod, EMOD_FMRI_VERSION));
@@ -329,13 +328,40 @@ topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
*/
if (auth != NULL)
(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
- if (part != NULL)
- (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART, part);
- if (rev != NULL)
- (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV, rev);
- if (serial != NULL)
- (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
- serial);
+ if (part != NULL) {
+ lpart = topo_cleanup_auth_str(mod->tm_hdl, part);
+ if (lpart != NULL) {
+ (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
+ lpart);
+ topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1);
+ } else {
+ (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
+ part);
+ }
+ }
+ if (rev != NULL) {
+ lrev = topo_cleanup_auth_str(mod->tm_hdl, rev);
+ if (lrev != NULL) {
+ (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
+ lrev);
+ topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1);
+ } else {
+ (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
+ rev);
+ }
+ }
+ if (serial != NULL) {
+ lserial = topo_cleanup_auth_str(mod->tm_hdl, serial);
+ if (lserial != NULL) {
+ (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
+ lserial);
+ topo_hdl_free(mod->tm_hdl, lserial,
+ strlen(lserial) + 1);
+ } else {
+ (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
+ serial);
+ }
+ }
if (hc_specific != NULL)
(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
hc_specific);
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
index cc0d5b6faa..cadbe7c75c 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Snapshot Library Interfaces
*
@@ -188,7 +186,7 @@ topo_open(int version, const char *rootdir, int *errp)
if (strcmp(s2.smbi_product, SMB_DEFAULT1) != 0 &&
strcmp(s2.smbi_product, SMB_DEFAULT2) != 0) {
thp->th_product = topo_cleanup_auth_str(thp,
- (char *)s2.smbi_product);
+ s2.smbi_product);
}
}
smbios_close(shp);
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_subr.c b/usr/src/lib/fm/topo/libtopo/common/topo_subr.c
index e1c9e6fcc2..a795006afa 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_subr.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_subr.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <alloca.h>
#include <ctype.h>
#include <limits.h>
@@ -322,11 +320,13 @@ topo_search_path(topo_mod_t *mod, const char *rootdir, const char *file)
* so we translate that to '-'.
*/
char *
-topo_cleanup_auth_str(topo_hdl_t *thp, char *begin)
+topo_cleanup_auth_str(topo_hdl_t *thp, const char *begin)
{
char buf[MAXNAMELEN];
- size_t count;
- char *str, *end, *pp;
+ const char *end, *cp;
+ char *pp;
+ char c;
+ int i;
end = begin + strlen(begin);
@@ -338,15 +338,19 @@ topo_cleanup_auth_str(topo_hdl_t *thp, char *begin)
if (begin >= end)
return (NULL);
- count = end - begin;
- count += 1;
-
- if (count > sizeof (buf))
- return (NULL);
-
- (void) snprintf(buf, count, "%s", begin);
- while ((str = strpbrk(buf, " :=/")) != NULL)
- *str = '-';
+ cp = begin;
+ for (i = 0; i < MAXNAMELEN - 1; i++) {
+ if (cp >= end)
+ break;
+ c = *cp;
+ if (c == ':' || c == '=' || c == '/' || isspace(c) ||
+ !isprint(c))
+ buf[i] = '-';
+ else
+ buf[i] = c;
+ cp++;
+ }
+ buf[i] = 0;
pp = topo_hdl_strdup(thp, buf);
return (pp);
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_subr.h b/usr/src/lib/fm/topo/libtopo/common/topo_subr.h
index b4934241d4..5bcda4d93a 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_subr.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_subr.h
@@ -27,8 +27,6 @@
#ifndef _TOPO_SUBR_H
#define _TOPO_SUBR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <fm/libtopo.h>
#include <topo_list.h>
@@ -141,7 +139,7 @@ extern int topo_walk_byid(topo_walk_t *wp, const char *name, topo_instance_t);
extern int topo_walk_bysibling(topo_walk_t *wp, const char *name,
topo_instance_t);
-extern char *topo_cleanup_auth_str(topo_hdl_t *, char *);
+extern char *topo_cleanup_auth_str(topo_hdl_t *, const char *);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml b/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml
index 21d0da88c0..715e98c2d8 100644
--- a/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml
+++ b/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml
@@ -23,12 +23,11 @@
CDDL HEADER END
- ident "%Z%%M% %I% %E% SMI"
-->
<topology name='chip' scheme='hc'>
- <range name='chip' min='0' max='100'>
+ <range name='chip' min='0' max='256'>
<set type='product'
setlist='Sun-Fire(TM)-X2100|W1100z-2100z|Sun-Ultra-20-Workstation|Ultra20-M2|Sun-Ultra-40-M2-Workstation'>
@@ -353,7 +352,7 @@
<range name='memory-controller' min='0' max='16'>
<dependents grouping='children'>
- <range name='dram-channel' min='0' max='1'>
+ <range name='dram-channel' min='0' max='3'>
<dependents grouping='children'>
<range name='chip-select' min='0' max='7'>
diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c
index b421078273..4f375340c9 100644
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -71,6 +69,11 @@ static const topo_pgroup_info_t chip_pgroup =
{ PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
static const topo_pgroup_info_t cpu_pgroup =
{ PGNAME(CPU), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
+static const topo_pgroup_info_t cpu_core_pgroup =
+ { PGNAME(CPU_CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
+static const topo_pgroup_info_t cpu_strand_pgroup =
+ { PGNAME(CPU_STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE,
+ 1 };
static const topo_method_t chip_methods[] = {
{ SIMPLE_CHIP_LBL, "Property method", 0,
@@ -139,6 +142,163 @@ _topo_fini(topo_mod_t *mod)
}
static int
+cpu_strand_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
+ int coreid, chip_t *chip, int nstrand, nvlist_t *auth)
+{
+ kstat_named_t *k;
+ nvlist_t *fmri, *asru;
+ tnode_t *cnode;
+ int err, nerr = 0;
+ int cpuid, clogid, tcoreid, strandid;
+
+ if (topo_node_range_create(mod, pnode, name, 0,
+ nstrand) < 0)
+ return (-1);
+
+ for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) {
+ if (chip->chip_cpustats[cpuid] == NULL)
+ continue;
+
+ /*
+ * The chip_id in the cpu_info kstat numbers the individual
+ * chips from 0 to #chips - 1.
+ */
+ if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
+ "chip_id")) == NULL) {
+ whinge(mod, &nerr,
+ "cpu_strand_create: chip_id lookup via "
+ "kstats failed\n");
+ continue;
+ }
+
+ if (k->value.l != chipid)
+ continue; /* not an error */
+
+ if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
+ "clog_id")) == NULL) {
+ whinge(mod, &nerr,
+ "cpu_strand_create: clog_id lookup via "
+ "kstats failed\n");
+ continue;
+ }
+ clogid = k->value.l;
+ tcoreid = clogid / nstrand;
+
+ if (coreid != tcoreid)
+ continue;
+
+ strandid = clogid % nstrand;
+
+ if (mkrsrc(mod, pnode, name, strandid, auth, &fmri) != 0) {
+ whinge(mod, &nerr,
+ "cpu_strand_create: mkrsrc failed\n");
+ continue;
+ }
+
+ if ((cnode = topo_node_bind(mod, pnode, name, strandid, fmri))
+ == NULL) {
+ whinge(mod, &nerr,
+ "cpu_strand_create: node bind failed\n");
+ nvlist_free(fmri);
+ continue;
+ }
+ nvlist_free(fmri);
+
+ if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) {
+ (void) topo_node_asru_set(cnode, asru, 0, &err);
+ nvlist_free(asru);
+ } else {
+ whinge(mod, &nerr, "cpu_strand_create: cpu_fmri_create "
+ "failed\n");
+ }
+ (void) topo_node_fru_set(cnode, NULL, 0, &err);
+
+ (void) topo_pgroup_create(cnode, &cpu_strand_pgroup, &err);
+
+ (void) topo_prop_set_uint32(cnode, PGNAME(CPU_STRAND), "cpuid",
+ TOPO_PROP_IMMUTABLE, cpuid, &err);
+
+ if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid],
+ PGNAME(CPU_STRAND), NULL, CPU_CHIP_ID, CPU_CORE_ID,
+ CPU_CLOG_ID, CPU_PKG_CORE_ID, NULL) != 0)
+ nerr++; /* have whinged elsewhere */
+ }
+
+ return (nerr == 0 ? 0 : -1);
+}
+
+static int
+cpu_core_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
+ chip_t *chip, int ncore, int ncpu, nvlist_t *auth)
+{
+ kstat_named_t *k;
+ nvlist_t *fmri;
+ tnode_t *cnode;
+ int clogid, cpuid, coreid;
+ int nstrand;
+ int err, nerr = 0;
+
+ if (topo_node_range_create(mod, pnode, name, 0,
+ ncore) < 0)
+ return (-1);
+
+ nstrand = ncpu / ncore;
+ for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) {
+ if (chip->chip_cpustats[cpuid] == NULL)
+ continue;
+
+ /*
+ * The chip_id in the cpu_info kstat numbers the individual
+ * chips from 0 to #chips - 1.
+ */
+ if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
+ "chip_id")) == NULL) {
+ whinge(mod, &nerr,
+ "cpu_core_create: chip_id lookup via "
+ "kstats failed\n");
+ continue;
+ }
+
+ if (k->value.l != chipid)
+ continue; /* not an error */
+
+ if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid],
+ "clog_id")) == NULL) {
+ whinge(mod, &nerr,
+ "cpu_core_create: clog_id lookup via "
+ "kstats failed\n");
+ continue;
+ }
+ clogid = k->value.l;
+ coreid = clogid / nstrand;
+
+ if (mkrsrc(mod, pnode, name, coreid, auth, &fmri) != 0) {
+ whinge(mod, &nerr, "cpu_core_create: mkrsrc failed\n");
+ continue;
+ }
+
+ if ((cnode = topo_node_bind(mod, pnode, name, coreid, fmri))
+ == NULL) {
+ whinge(mod, &nerr,
+ "cpu_core_create: node bind failed\n");
+ nvlist_free(fmri);
+ continue;
+ }
+ nvlist_free(fmri);
+
+ (void) topo_node_fru_set(cnode, NULL, 0, &err);
+
+ (void) topo_pgroup_create(cnode, &cpu_core_pgroup, &err);
+
+ if (cpu_strand_create(mod, cnode, CPU_STRAND_NODE_NAME, chipid,
+ coreid, chip, nstrand, auth) != 0)
+ nerr++; /* have whinged elsewhere */
+ }
+
+ return (nerr == 0 ? 0 : -1);
+}
+
+static int
cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
chip_t *chip, nvlist_t *auth)
{
@@ -229,13 +389,15 @@ cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid,
static int
chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
- topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth)
+ topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth,
+ int mc_offchip)
{
int i, nerr = 0;
kstat_t *ksp;
ulong_t *chipmap;
tnode_t *cnode;
nvlist_t *fmri;
+ int ncore, ncpu;
if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(max) *
sizeof (ulong_t))) == NULL)
@@ -307,8 +469,32 @@ chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL) != 0)
nerr++; /* have whinged elsewhere */
- if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip, auth)
- != 0)
+ if ((k = kstat_data_lookup(ksp, "ncore_per_chip")) == NULL) {
+ whinge(mod, &nerr, "chip_create: ncore_per_chip lookup "
+ "via kstats failed\n");
+ ncore = 0;
+ ncpu = 0;
+ } else {
+ ncore = k->value.l;
+
+ if ((k = kstat_data_lookup(ksp,
+ "ncpu_per_chip")) == NULL) {
+ whinge(mod, &nerr,
+ "chip_create: ncpu_per_chip lookup "
+ "via kstats failed\n");
+ ncore = 0;
+ ncpu = 0;
+ } else {
+ ncpu = k->value.l;
+ }
+ }
+
+ if (ncore < ncpu) {
+ if (cpu_core_create(mod, cnode, CPU_CORE_NODE_NAME,
+ chipid, chip, ncore, ncpu, auth) != 0)
+ nerr++; /* have whinged elsewhere */
+ } else if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip,
+ auth) != 0)
nerr++; /* have whinged elsewhere */
/*
@@ -318,6 +504,8 @@ chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
if (strcmp(vendor, "AuthenticAMD") == 0)
amd_mc_create(mod, cnode, MCT_NODE_NAME, auth,
fms[0], fms[1], fms[2], &nerr);
+ else if (!mc_offchip)
+ onchip_mc_create(mod, cnode, MCT_NODE_NAME, auth);
}
topo_mod_free(mod, chipmap, BT_BITOUL(max) * sizeof (ulong_t));
@@ -338,15 +526,16 @@ chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
int rv = 0;
chip_t *chip = (chip_t *)arg;
nvlist_t *auth = NULL;
- int intel_mc;
+ int offchip_mc;
auth = topo_mod_auth(mod, pnode);
- intel_mc = mc_offchip_open();
+ offchip_mc = mc_offchip_open();
if (strcmp(name, CHIP_NODE_NAME) == 0)
- rv = chip_create(mod, pnode, name, min, max, chip, auth);
+ rv = chip_create(mod, pnode, name, min, max, chip, auth,
+ offchip_mc);
- if (intel_mc)
+ if (offchip_mc)
(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
nvlist_free(auth);
diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h
index 637b90ac4b..b9b5b9b899 100644
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h
@@ -26,8 +26,6 @@
#ifndef _CHIP_H
#define _CHIP_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <kstat.h>
#include <libnvpair.h>
#include <fm/libtopo.h>
@@ -43,6 +41,8 @@ extern "C" {
#define MCT_NODE_NAME "memory-controller"
#define CHAN_NODE_NAME "dram-channel"
#define CPU_NODE_NAME "cpu"
+#define CPU_CORE_NODE_NAME "core"
+#define CPU_STRAND_NODE_NAME "strand"
#define CS_NODE_NAME "chip-select"
#define DIMM_NODE_NAME "dimm"
#define RANK_NODE_NAME "rank"
@@ -153,11 +153,11 @@ extern void amd_mc_create(topo_mod_t *, tnode_t *, const char *, nvlist_t *,
*/
extern int mc_offchip_open(void);
extern int mc_offchip_create(topo_mod_t *, tnode_t *, const char *, nvlist_t *);
+extern void onchip_mc_create(topo_mod_t *, tnode_t *, const char *, nvlist_t *);
extern char *get_fmtstr(topo_mod_t *, nvlist_t *);
extern int store_prop_val(topo_mod_t *, char *, char *, nvlist_t **out);
-
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c
index c64c576df1..b71e40bd9e 100644
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -89,9 +87,20 @@ mc_offchip_open()
return (mc_fd != -1);
}
+static int
+mc_onchip(topo_instance_t id)
+{
+ char path[64];
+
+ (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id);
+ mc_fd = open(path, O_RDONLY);
+ return (mc_fd != -1);
+}
+
void
mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm,
- nvlist_t **ranks_nvp, int nranks, char *serial, char *part, char *rev)
+ nvlist_t **ranks_nvp, int nranks, char *serial, char *part, char *rev,
+ int maxranks)
{
int i;
int rank;
@@ -100,7 +109,7 @@ mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm,
nvlist_t *fmri;
int err = 0;
- rank = dimm * 2;
+ rank = dimm * maxranks;
if (topo_node_range_create(mod, dnode, RANK, rank,
rank + nranks - 1) < 0) {
whinge(mod, NULL, "mc_add_dimms: node range create failed"
@@ -143,7 +152,7 @@ mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm,
static void
mc_add_dimms(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth,
- nvlist_t **nvl, uint_t ndimms)
+ nvlist_t **nvl, uint_t ndimms, int maxranks)
{
int i;
nvlist_t *fmri;
@@ -218,18 +227,20 @@ mc_add_dimms(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth,
if (nranks) {
mc_add_ranks(mod, dnode, auth, i, ranks_nvp, nranks,
- serial, part, rev);
+ serial, part, rev, maxranks);
}
}
}
static int
mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth,
- nvlist_t *nvl)
+ nvlist_t *nvl, int maxranks)
{
tnode_t *mc_channel;
nvlist_t *fmri;
nvlist_t **dimm_nvl;
+ nvpair_t *nvp;
+ char *name;
uint_t ndimms;
int err;
@@ -249,7 +260,15 @@ mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth,
(void) topo_pgroup_create(mc_channel, &dimm_channel_pgroup, &err);
if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_DIMMS, &dimm_nvl,
&ndimms) == 0) {
- mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms);
+ mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms, maxranks);
+ }
+ for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+ name = nvpair_name(nvp);
+ if (strcmp(name, MCINTEL_NVLIST_DIMMS) != 0) {
+ (void) nvprop_add(mod, nvp, PGNAME(CHAN),
+ mc_channel);
+ }
}
return (0);
}
@@ -261,10 +280,13 @@ mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth,
int err;
int i, j;
int channel;
- int nmc;
+ uint8_t nmc;
+ uint8_t maxranks;
tnode_t *mcnode;
nvlist_t *fmri;
nvlist_t **channel_nvl;
+ nvpair_t *nvp;
+ char *pname;
uint_t nchannels;
if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_MC, &channel_nvl,
@@ -273,7 +295,18 @@ mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth,
"mc_nb_create: failed to find channel information\n");
return (-1);
}
- nmc = nchannels / 2;
+ if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NMEM, &nmc) != 0) {
+ /*
+ * if number of memory controllers is not specified then there
+ * are two channels per controller and the nchannels is total
+ * we will set up nmc as number of controllers and convert
+ * nchannels to channels per controller
+ */
+ nmc = nchannels / 2;
+ nchannels = nchannels / nmc;
+ }
+ if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NRANKS, &maxranks) != 0)
+ maxranks = 2;
if (topo_node_range_create(mod, pnode, name, 0, nmc-1) < 0) {
whinge(mod, NULL,
"mc_nb_create: node range create failed\n");
@@ -287,7 +320,7 @@ mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth,
}
if ((mcnode = topo_node_bind(mod, pnode, name, i,
fmri)) == NULL) {
- whinge(mod, NULL, "chip_create: node bind failed"
+ whinge(mod, NULL, "mc_nb_create: node bind failed"
" for memory-controller\n");
nvlist_free(fmri);
return (-1);
@@ -298,25 +331,37 @@ mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth,
(void) topo_pgroup_create(mcnode, &mc_pgroup, &err);
if (topo_node_range_create(mod, mcnode, DRAMCHANNEL, channel,
- channel + 1) < 0) {
+ channel + nchannels - 1) < 0) {
whinge(mod, NULL,
"mc_nb_create: channel node range create failed\n");
return (-1);
}
- for (j = 0; j < 2; j++) {
+ for (j = 0; j < nchannels; j++) {
if (mc_add_channel(mod, mcnode, channel, auth,
- channel_nvl[channel]) < 0) {
+ channel_nvl[channel], maxranks) < 0) {
return (-1);
}
channel++;
}
+ for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+ pname = nvpair_name(nvp);
+ if (strcmp(pname, MCINTEL_NVLIST_MC) != 0 &&
+ strcmp(pname, MCINTEL_NVLIST_NMEM) != 0 &&
+ strcmp(pname, MCINTEL_NVLIST_NRANKS) != 0 &&
+ strcmp(pname, MCINTEL_NVLIST_VERSTR) != 0 &&
+ strcmp(pname, MCINTEL_NVLIST_MEM) != 0) {
+ (void) nvprop_add(mod, nvp, PGNAME(MCT),
+ mcnode);
+ }
+ }
}
return (NULL);
}
int
-mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
+mc_node_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
nvlist_t *auth)
{
mc_snapshot_info_t mcs;
@@ -355,3 +400,18 @@ mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
nvlist_free(nvl);
return (rc);
}
+
+void
+onchip_mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
+ nvlist_t *auth)
+{
+ if (mc_onchip(topo_node_instance(pnode)))
+ (void) mc_node_create(mod, pnode, name, auth);
+}
+
+int
+mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
+ nvlist_t *auth)
+{
+ return (mc_node_create(mod, pnode, name, auth));
+}
diff --git a/usr/src/pkgdefs/SUNWcakr.i/prototype_com b/usr/src/pkgdefs/SUNWcakr.i/prototype_com
index c35e78e315..ba51653f00 100644
--- a/usr/src/pkgdefs/SUNWcakr.i/prototype_com
+++ b/usr/src/pkgdefs/SUNWcakr.i/prototype_com
@@ -22,8 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
@@ -74,6 +72,7 @@ f none platform/i86pc/kernel/drv/amd64/isa 755 root sys
f none platform/i86pc/kernel/drv/amd64/mc-amd 755 root sys
f none platform/i86pc/kernel/drv/amd64/npe 755 root sys
f none platform/i86pc/kernel/drv/amd64/intel_nb5000 755 root sys
+f none platform/i86pc/kernel/drv/amd64/intel_nhm 755 root sys
f none platform/i86pc/kernel/drv/amd64/pci 755 root sys
f none platform/i86pc/kernel/drv/amd64/pit_beep 755 root sys
f none platform/i86pc/kernel/drv/amd64/rootnex 755 root sys
@@ -83,6 +82,8 @@ f none platform/i86pc/kernel/drv/mc-amd 755 root sys
f none platform/i86pc/kernel/drv/mc-amd.conf 644 root sys
f none platform/i86pc/kernel/drv/intel_nb5000 755 root sys
f none platform/i86pc/kernel/drv/intel_nb5000.conf 644 root sys
+f none platform/i86pc/kernel/drv/intel_nhm 755 root sys
+f none platform/i86pc/kernel/drv/intel_nhm.conf 644 root sys
f none platform/i86pc/kernel/drv/npe 755 root sys
f none platform/i86pc/kernel/drv/pci 755 root sys
f none platform/i86pc/kernel/drv/pit_beep 755 root sys
diff --git a/usr/src/uts/i86pc/Makefile.i86pc.shared b/usr/src/uts/i86pc/Makefile.i86pc.shared
index 4d188a4dfd..95820fe60a 100644
--- a/usr/src/uts/i86pc/Makefile.i86pc.shared
+++ b/usr/src/uts/i86pc/Makefile.i86pc.shared
@@ -25,8 +25,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This makefile contains the common definitions for the i86pc unix
# and all i86pc implementation architecture dependent modules.
#
@@ -276,6 +274,7 @@ CPU_KMODS += generic_cpu
CPU_KMODS += authenticamd
CPU_KMODS += genuineintel
CPU_KMODS += intel_nb5000
+CPU_KMODS += intel_nhm
#
# Exec Class Modules (/kernel/exec):
diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules
index c70d7a09ed..a064af6ed7 100644
--- a/usr/src/uts/i86pc/Makefile.rules
+++ b/usr/src/uts/i86pc/Makefile.rules
@@ -63,6 +63,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/intel_nb5000/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/intel_nhm/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -260,6 +264,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/genuineintel/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/intel_nb5000/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/intel_nhm/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h
index 5e826593d9..789587f826 100644
--- a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _GCPU_H
#define _GCPU_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/cpu_module_impl.h>
#include <sys/cpu_module_ms.h>
@@ -114,6 +112,8 @@ struct gcpu_bios_cfg {
#define GCPU_MPT_WHAT_CYC_ERR 0 /* cyclic-induced poll */
#define GCPU_MPT_WHAT_POKE_ERR 1 /* manually-induced poll */
#define GCPU_MPT_WHAT_UNFAULTING 2 /* discarded error state */
+#define GCPU_MPT_WHAT_MC_ERR 3 /* MC# */
+#define GCPU_MPT_WHAT_CMCI_ERR 4 /* CMCI interrupt */
typedef struct gcpu_mca_poll_trace {
hrtime_t mpt_when; /* timestamp of event */
@@ -128,6 +128,18 @@ typedef struct gcpu_mca_poll_trace_ctl {
uint_t mptc_curtrace; /* last buffer filled */
} gcpu_mca_poll_trace_ctl_t;
+
+/*
+ * For counting some of the important number or time for runtime
+ * cmci enable/disable
+ */
+typedef struct gcpu_mca_cmci {
+ uint32_t cmci_cap; /* cmci capability for this bank */
+ uint32_t ncmci; /* number of correctable errors between polls */
+ uint32_t drtcmci; /* duration of no cmci when cmci is disabled */
+ uint32_t cmci_enabled; /* cmci enable/disable status for this bank */
+} gcpu_mca_cmci_t;
+
/* Index for gcpu_mca_logout array below */
#define GCPU_MCA_LOGOUT_EXCEPTION 0 /* area for #MC */
#define GCPU_MCA_LOGOUT_POLLER_1 1 /* next/prev poll area */
@@ -144,6 +156,8 @@ typedef struct gcpu_mca {
uint_t gcpu_mca_flags; /* GCPU_MCA_F_* */
hrtime_t gcpu_mca_lastpoll;
gcpu_mca_poll_trace_ctl_t gcpu_mca_polltrace;
+ uint32_t gcpu_mca_first_poll_cmci_enabled; /* cmci on in first poll */
+ gcpu_mca_cmci_t *gcpu_bank_cmci;
} gcpu_mca_t;
typedef struct gcpu_mce_status {
@@ -193,15 +207,21 @@ extern void gcpu_faulted_exit(cmi_hdl_t);
extern void gcpu_mca_init(cmi_hdl_t);
extern cmi_errno_t gcpu_msrinject(cmi_hdl_t, cmi_mca_regs_t *, uint_t, int);
extern uint64_t gcpu_mca_trap(cmi_hdl_t, struct regs *);
+extern void gcpu_cmci_trap(cmi_hdl_t);
extern void gcpu_hdl_poke(cmi_hdl_t);
/*
+ * CMI global variable
+ */
+extern int cmi_enable_cmci;
+
+/*
* Local functions
*/
extern void gcpu_mca_poll_init(cmi_hdl_t);
extern void gcpu_mca_poll_start(cmi_hdl_t);
extern void gcpu_mca_logout(cmi_hdl_t, struct regs *, uint64_t,
- gcpu_mce_status_t *, boolean_t);
+ gcpu_mce_status_t *, boolean_t, int);
#endif /* _KERNEL */
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c
index 9cb5bcaff9..844d54fe53 100644
--- a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Generic x86 CPU Module
*
@@ -115,7 +113,7 @@ gcpu_post_mpstartup(cmi_hdl_t hdl)
}
}
-cmi_api_ver_t _cmi_api_version = CMI_API_VERSION_1;
+cmi_api_ver_t _cmi_api_version = CMI_API_VERSION_2;
const cmi_ops_t _cmi_ops = {
gcpu_init, /* cmi_init */
@@ -125,6 +123,7 @@ const cmi_ops_t _cmi_ops = {
gcpu_faulted_exit, /* cmi_faulted_exit */
gcpu_mca_init, /* cmi_mca_init */
gcpu_mca_trap, /* cmi_mca_trap */
+ gcpu_cmci_trap, /* cmi_cmci_trap */
gcpu_msrinject, /* cmi_msrinject */
gcpu_hdl_poke, /* cmi_hdl_poke */
NULL, /* cmi_fini */
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
index 1e20582c1f..312df47c5a 100644
--- a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/mca_x86.h>
#include <sys/cpu_module_impl.h>
#include <sys/cpu_module_ms.h>
@@ -73,6 +71,9 @@ int gcpu_mca_stack_ereport_include = 0;
*/
int gcpu_mca_telemetry_retries = 5;
+int gcpu_mca_cmci_throttling_threshold = 10;
+int gcpu_mca_cmci_reenable_threshold = 1000;
+
static gcpu_error_disp_t gcpu_errtypes[] = {
/*
@@ -120,6 +121,18 @@ static gcpu_error_disp_t gcpu_errtypes[] = {
},
/*
+ * Internal parity error
+ */
+ {
+ FM_EREPORT_CPU_GENERIC_INTERNAL_PARITY,
+ NULL,
+ FM_EREPORT_PAYLOAD_FLAGS_COMMON,
+ MCAX86_SIMPLE_INTERNAL_PARITY_MASKON,
+ MCAX86_SIMPLE_INTERNAL_PARITY_MASKOFF
+ },
+
+
+ /*
* Internal timer error
*/
{
@@ -184,6 +197,16 @@ static gcpu_error_disp_t gcpu_errtypes[] = {
MCAX86_COMPOUND_BUS_INTERCONNECT_MASKON,
MCAX86_COMPOUND_BUS_INTERCONNECT_MASKOFF
},
+ /*
+ * Compound error codes - memory controller errors
+ */
+ {
+ FM_EREPORT_CPU_GENERIC_MEMORY_CONTROLLER,
+ "MC" "_" "%8$s" "_" "%9$s" "_ERR",
+ FM_EREPORT_PAYLOAD_FLAGS_COMPOUND_ERR,
+ MCAX86_COMPOUND_MEMORY_CONTROLLER_MASKON,
+ MCAX86_COMPOUND_MEMORY_CONTROLLER_MASKOFF
+ },
};
static gcpu_error_disp_t gcpu_unknown = {
@@ -283,6 +306,36 @@ static struct gcpu_mnexp gcpu_T_mnemonics[] = { /* MCAX86_ERRCODE_T_* */
{ "TIMEOUT", FM_EREPORT_CPU_GENERIC_T_TIMEOUT } /* TIMEOUT */
};
+static struct gcpu_mnexp gcpu_CCCC_mnemonics[] = { /* MCAX86_ERRCODE_CCCC_* */
+ { "CH0", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH0 */
+ { "CH1", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH1 */
+ { "CH2", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH2 */
+ { "CH3", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH3 */
+ { "CH4", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH4 */
+ { "CH5", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH5 */
+ { "CH6", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH6 */
+ { "CH7", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH7 */
+ { "CH8", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH8 */
+ { "CH9", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH9 */
+ { "CH10", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH10 */
+ { "CH11", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH11 */
+ { "CH12", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH12 */
+ { "CH13", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH13 */
+ { "CH14", FM_EREPORT_CPU_GENERIC_CCCC }, /* CH14 */
+ { "CH", FM_EREPORT_CPU_GENERIC_CCCC } /* GEN */
+};
+
+static struct gcpu_mnexp gcpu_MMM_mnemonics[] = { /* MCAX86_ERRCODE_MMM_* */
+ { "GEN", FM_EREPORT_CPU_GENERIC_MMM_ERR }, /* GEN ERR */
+ { "RD", FM_EREPORT_CPU_GENERIC_MMM_RD }, /* READ */
+ { "WR", FM_EREPORT_CPU_GENERIC_MMM_WR }, /* WRITE */
+ { "ADDR_CMD", FM_EREPORT_CPU_GENERIC_MMM_ADRCMD }, /* ADDR, CMD */
+ { GCPU_MNEMONIC_RESVD, ""}, /* RESERVED */
+ { GCPU_MNEMONIC_RESVD, ""}, /* RESERVED */
+ { GCPU_MNEMONIC_RESVD, ""}, /* RESERVED */
+ { GCPU_MNEMONIC_RESVD, ""} /* RESERVED */
+};
+
enum gcpu_mn_namespace {
GCPU_MN_NAMESPACE_COMPOUND,
GCPU_MN_NAMESPACE_EREPORT
@@ -318,7 +371,7 @@ gcpu_mnemonic(const struct gcpu_mnexp *tbl, size_t tbl_sz, uint8_t val,
* we will expand this restricted format string ourselves.
*/
-#define GCPU_CLASS_VARCOMPS 7
+#define GCPU_CLASS_VARCOMPS 9
#define GCPU_MNEMONIC(code, name, nspace) \
gcpu_mnemonic(gcpu_##name##_mnemonics, \
@@ -343,6 +396,8 @@ gcpu_mn_fmt(const char *fmt, char *buf, size_t buflen, uint64_t status,
mn[4] = GCPU_MNEMONIC(code, II, nspace);
mn[5] = GCPU_MNEMONIC(code, T, nspace);
mn[6] = (status & MSR_MC_STATUS_UC) ? "_uc" : "";
+ mn[7] = GCPU_MNEMONIC(code, CCCC, nspace);
+ mn[8] = GCPU_MNEMONIC(code, MMM, nspace);
while (p < q - 1 && (c = *fmt++) != '\0') {
if (c != '%') {
@@ -367,6 +422,8 @@ nextfmt:
case '5':
case '6':
case '7':
+ case '8':
+ case '9':
if (which != -1) { /* allow only one positional digit */
error++;
break;
@@ -430,9 +487,9 @@ gcpu_erpt_clsfmt(const char *fmt, char *buf, size_t buflen, uint64_t status,
}
/*
- * Create an "hc" scheme FMRI identifying the given cpu. We don't know
+ * Create an "hc" scheme FMRI identifying the given cpu. If we don't know
* the actual topology/connectivity of cpus in the system, so we'll
- * apply /motherboard=0/chip=.../cpu=... in all cases.
+ * apply /motherboard=0/chip=.../cpu=...
*/
static nvlist_t *
gcpu_fmri_create(cmi_hdl_t hdl, nv_alloc_t *nva)
@@ -442,10 +499,18 @@ gcpu_fmri_create(cmi_hdl_t hdl, nv_alloc_t *nva)
if ((nvl = fm_nvlist_create(nva)) == NULL)
return (NULL);
- fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
- "motherboard", 0,
- "chip", cmi_hdl_chipid(hdl),
- "cpu", cmi_hdl_coreid(hdl));
+ if (cmi_hdl_mstrand(hdl)) {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 4,
+ "motherboard", 0,
+ "chip", cmi_hdl_chipid(hdl),
+ "core", cmi_hdl_coreid(hdl),
+ "strand", cmi_hdl_strandid(hdl));
+ } else {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
+ "motherboard", 0,
+ "chip", cmi_hdl_chipid(hdl),
+ "cpu", cmi_hdl_coreid(hdl));
+ }
return (nvl);
}
@@ -482,8 +547,10 @@ gcpu_bleat(cmi_hdl_t hdl, gcpu_logout_t *gcl)
}
gcpu_last_bleat = now;
- cmn_err(CE_WARN, "Machine-Check Errors unlogged on chip %d core %d, "
- "raw dump follows", cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl));
+ cmn_err(CE_WARN,
+ "Machine-Check Errors unlogged on chip %d core %d strand %d, "
+ "raw dump follows", cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
+ cmi_hdl_strandid(hdl));
cmn_err(CE_WARN, "MCG_STATUS 0x%016llx",
(u_longlong_t)gcl->gcl_mcg_status);
for (i = 0, gbl = &gcl->gcl_data[0]; i < gcl->gcl_nbanks; i++, gbl++) {
@@ -937,6 +1004,8 @@ gcpu_mca_init(cmi_hdl_t hdl)
uint_t nbanks;
size_t mslsz;
int i;
+ int mcg_misc2_present;
+ uint32_t cmci_capable = 0;
if (gcpu == NULL)
return;
@@ -969,6 +1038,7 @@ gcpu_mca_init(cmi_hdl_t hdl)
* banks.
*/
mcg_ctl_present = cap & MCG_CAP_CTL_P;
+ mcg_misc2_present = cap & MCG_CAP_MISC2_P;
/*
* We squirell values away for inspection/debugging.
@@ -1023,6 +1093,9 @@ gcpu_mca_init(cmi_hdl_t hdl)
}
mca->gcpu_mca_nextpoll_idx = GCPU_MCA_LOGOUT_POLLER_1;
+ mca->gcpu_bank_cmci = kmem_zalloc(sizeof (gcpu_mca_cmci_t) * nbanks,
+ KM_SLEEP);
+
/*
* Create our errorq to transport the logout structures. This
* can fail so users of gcpu_mca_queue must be prepared for NULL.
@@ -1055,13 +1128,15 @@ gcpu_mca_init(cmi_hdl_t hdl)
*/
for (i = 0; i < nbanks; i++) {
/*
- * On Intel family 6 and AMD family 6 we must not enable
- * machine check from bank 0 detectors. In the Intel
- * case bank 0 is reserved for the platform, while in the
+ * On AMD family 6 we must not enable
+ * machine check from bank 0 detectors.
* AMD case reports are that enabling bank 0 (DC) produces
* spurious machine checks.
+ * For Intel we let plug-in choose to skip bank if plug-in
+ * is enabled otherwise we skip bank 0 for family 6
*/
- if (i == 0 && ((vendor == X86_VENDOR_Intel ||
+ if (i == 0 &&
+ (((vendor == X86_VENDOR_Intel && !cms_present(hdl)) ||
vendor == X86_VENDOR_AMD) && family == 6))
continue;
@@ -1076,7 +1151,40 @@ gcpu_mca_init(cmi_hdl_t hdl)
*/
mca->gcpu_actv_banks |= 1 << i;
atomic_or_32(&gcpu->gcpu_shared->gcpus_actv_banks, 1 << i);
+
+ /*
+ * check CMCI capability
+ */
+ if (mcg_misc2_present) {
+ uint64_t misc2;
+ uint32_t cap = 0;
+ (void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC_MISC2(i), &misc2);
+ if (misc2 & MSR_MC_MISC2_EN)
+ continue;
+ misc2 |= MSR_MC_MISC2_EN;
+ (void) cmi_hdl_wrmsr(hdl, IA32_MSR_MC_MISC2(i), misc2);
+ (void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC_MISC2(i), &misc2);
+ mca->gcpu_bank_cmci[i].cmci_cap = cap =
+ (misc2 & MSR_MC_MISC2_EN) ? 1 : 0;
+ if (cap)
+ cmci_capable ++;
+ /*
+ * Set threshold to 1 while unset the en field, to avoid
+ * CMCI trigged before APIC LVT entry init.
+ */
+ misc2 = misc2 & (~MSR_MC_MISC2_EN) | 1;
+ (void) cmi_hdl_wrmsr(hdl, IA32_MSR_MC_MISC2(i), misc2);
+
+ /*
+ * init cmci related count
+ */
+ mca->gcpu_bank_cmci[i].cmci_enabled = 0;
+ mca->gcpu_bank_cmci[i].drtcmci = 0;
+ mca->gcpu_bank_cmci[i].ncmci = 0;
+ }
}
+ if (cmci_capable)
+ cmi_enable_cmci = 1;
/*
* Log any valid telemetry lurking in the MCA banks, but do not
@@ -1094,7 +1202,8 @@ gcpu_mca_init(cmi_hdl_t hdl)
if (!gcpu_suppress_log_on_init &&
(vendor == X86_VENDOR_Intel && family >= 0xf ||
vendor == X86_VENDOR_AMD))
- gcpu_mca_logout(hdl, NULL, -1ULL, NULL, B_FALSE);
+ gcpu_mca_logout(hdl, NULL, -1ULL, NULL, B_FALSE,
+ GCPU_MPT_WHAT_POKE_ERR);
/*
* Initialize all MCi_CTL and clear all MCi_STATUS, allowing the
@@ -1319,9 +1428,89 @@ gcpu_mca_process(cmi_hdl_t hdl, struct regs *rp, int nerr, gcpu_data_t *gcpu,
static uint32_t gcpu_deferrred_polled_clears;
+static void
+gcpu_cmci_logout(cmi_hdl_t hdl, int bank, gcpu_mca_cmci_t *bank_cmci_p,
+ uint64_t status, int what)
+{
+ uint64_t misc2;
+
+ if (bank_cmci_p->cmci_cap && (what == GCPU_MPT_WHAT_CYC_ERR) &&
+ (!(status & MSR_MC_STATUS_VAL) || ((status & MSR_MC_STATUS_VAL) &&
+ !(status & MSR_MC_STATUS_CEC_MASK)))) {
+
+ if (!(bank_cmci_p->cmci_enabled)) {
+ /*
+ * when cmci is disabled, and the bank has no error or
+ * no corrected error for
+ * gcpu_mca_cmci_reenable_threshold consecutive polls,
+ * turn on this bank's cmci.
+ */
+
+ bank_cmci_p->drtcmci ++;
+
+ if (bank_cmci_p->drtcmci >=
+ gcpu_mca_cmci_reenable_threshold) {
+
+ /* turn on cmci */
+
+ (void) cmi_hdl_rdmsr(hdl,
+ IA32_MSR_MC_MISC2(bank), &misc2);
+ misc2 |= MSR_MC_MISC2_EN;
+ (void) cmi_hdl_wrmsr(hdl,
+ IA32_MSR_MC_MISC2(bank), misc2);
+
+ /* reset counter and set flag */
+ bank_cmci_p->drtcmci = 0;
+ bank_cmci_p->cmci_enabled = 1;
+ }
+ } else {
+ /*
+ * when cmci is enabled,if is in cyclic poll and the
+ * bank has no error or no corrected error, reset ncmci
+ * counter
+ */
+ bank_cmci_p->ncmci = 0;
+ }
+ }
+}
+
+static void
+gcpu_cmci_throttle(cmi_hdl_t hdl, int bank, gcpu_mca_cmci_t *bank_cmci_p,
+ int what)
+{
+ uint64_t misc2 = 0;
+
+ /*
+ * if cmci of this bank occurred beyond
+ * gcpu_mca_cmci_throttling_threshold between 2 polls,
+ * turn off this bank's CMCI;
+ */
+ if (bank_cmci_p->cmci_enabled && what == GCPU_MPT_WHAT_CMCI_ERR) {
+
+ /* if it is cmci trap, increase the count */
+ bank_cmci_p->ncmci++;
+
+ if (bank_cmci_p->ncmci >= gcpu_mca_cmci_throttling_threshold) {
+
+ /* turn off cmci */
+
+ (void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC_MISC2(bank),
+ &misc2);
+ misc2 &= ~MSR_MC_MISC2_EN;
+ (void) cmi_hdl_wrmsr(hdl, IA32_MSR_MC_MISC2(bank),
+ misc2);
+
+ /* clear the flag and count */
+
+ bank_cmci_p->cmci_enabled = 0;
+ bank_cmci_p->ncmci = 0;
+ }
+ }
+}
+
void
gcpu_mca_logout(cmi_hdl_t hdl, struct regs *rp, uint64_t bankmask,
- gcpu_mce_status_t *mcesp, boolean_t clrstatus)
+ gcpu_mce_status_t *mcesp, boolean_t clrstatus, int what)
{
gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl);
gcpu_mca_t *mca = &gcpu->gcpu_mca;
@@ -1391,6 +1580,9 @@ gcpu_mca_logout(cmi_hdl_t hdl, struct regs *rp, uint64_t bankmask,
if (cmi_hdl_rdmsr(hdl, IA32_MSR_MC(i, STATUS), &status) !=
CMI_SUCCESS)
continue;
+
+ gcpu_cmci_logout(hdl, i, &mca->gcpu_bank_cmci[i], status, what);
+
retry:
if (!(status & MSR_MC_STATUS_VAL))
continue;
@@ -1404,6 +1596,8 @@ retry:
if (status & MSR_MC_STATUS_MISCV)
(void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC(i, MISC), &misc);
+ gcpu_cmci_throttle(hdl, i, &mca->gcpu_bank_cmci[i], what);
+
/*
* Allow the model-specific code to extract bank telemetry.
*/
@@ -1601,7 +1795,7 @@ gcpu_mca_trap(cmi_hdl_t hdl, struct regs *rp)
tooklock = 1;
}
- gcpu_mca_logout(hdl, rp, 0, &mce, B_TRUE);
+ gcpu_mca_logout(hdl, rp, 0, &mce, B_TRUE, GCPU_MPT_WHAT_MC_ERR);
if (tooklock)
mutex_exit(poll_lock);
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c
index 1cbbc930fa..b52c519483 100644
--- a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Generic x86 CPU MCA poller.
*/
@@ -118,9 +116,27 @@ gcpu_ntv_mca_poll(cmi_hdl_t hdl, int what)
gcpu_mca_poll_trace_ctl_t *ptc = &gcpu->gcpu_mca.gcpu_mca_polltrace;
gcpu_mce_status_t mce;
int willpanic;
+ int i;
+ uint64_t misc2;
+ uint64_t bankmask;
ASSERT(MUTEX_HELD(&gcpu->gcpu_shared->gcpus_poll_lock));
+ /* Enable CMCI in first poll if is support */
+ if (cmi_enable_cmci && (!mca->gcpu_mca_first_poll_cmci_enabled)) {
+ for (i = 0; i < mca->gcpu_mca_nbanks; i++) {
+ if (mca->gcpu_bank_cmci[i].cmci_cap) {
+ (void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC_MISC2(i),
+ &misc2);
+ misc2 |= MSR_MC_MISC2_EN;
+ (void) cmi_hdl_wrmsr(hdl, IA32_MSR_MC_MISC2(i),
+ misc2);
+ mca->gcpu_bank_cmci[i].cmci_enabled = 1;
+ }
+ }
+ mca->gcpu_mca_first_poll_cmci_enabled = 1;
+ }
+
if (mca->gcpu_mca_flags & GCPU_MCA_F_UNFAULTING) {
int i;
@@ -146,22 +162,31 @@ gcpu_ntv_mca_poll(cmi_hdl_t hdl, int what)
/*
* Logout errors of the MCA banks of this cpu.
*/
- gcpu_mca_logout(hdl, NULL,
- cms_poll_ownermask(hdl, gcpu_mca_poll_interval), &mce, B_TRUE);
+ if (what == GCPU_MPT_WHAT_CMCI_ERR) {
+ /*
+ * for CMCI, all banks should be scanned for log out
+ */
+ bankmask = -1ULL;
+ } else {
+ bankmask = cms_poll_ownermask(hdl, gcpu_mca_poll_interval);
+ }
+ gcpu_mca_logout(hdl, NULL, bankmask, &mce, B_TRUE, what);
gcpu_mca_poll_trace(ptc, what, mce.mce_nerr);
mca->gcpu_mca_lastpoll = gethrtime_waitfree();
willpanic = mce.mce_disp & CMI_ERRDISP_FORCEFATAL && cmi_panic_on_ue();
- /*
- * Call to the memory-controller driver which may report some
- * errors not visible under the MCA (for off-chip NB).
- * Since there is typically a single MCH we arrange that
- * just one cpu perform this task at each cyclic fire.
- */
- if (gcpu_mch_pollowner(hdl))
- cmi_mc_logout(hdl, 0, willpanic);
+ if (what != GCPU_MPT_WHAT_CMCI_ERR) {
+ /*
+ * Call to the memory-controller driver which may report some
+ * errors not visible under the MCA (for off-chip NB).
+ * Since there is typically a single MCH we arrange that
+ * just one cpu perform this task at each cyclic fire.
+ */
+ if (gcpu_mch_pollowner(hdl))
+ cmi_mc_logout(hdl, 0, willpanic);
+ }
/*
* In the common case any polled error is considered non-fatal,
@@ -362,3 +387,20 @@ gcpu_hdl_poke(cmi_hdl_t hdl)
break;
}
}
+
+void
+gcpu_cmci_trap(cmi_hdl_t hdl)
+{
+ switch (cmi_hdl_class(hdl)) {
+ case CMI_HDL_NATIVE:
+ gcpu_ntv_mca_poll_wrapper(hdl, GCPU_MPT_WHAT_CMCI_ERR);
+ break;
+
+ case CMI_HDL_SOLARIS_xVM_MCA:
+ /*
+ * Implementation will call the xPV poll wrapper.
+ */
+ default:
+ break;
+ }
+}
diff --git a/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c b/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c
index b954fe2d23..76b7abe467 100644
--- a/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c
+++ b/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Intel model-specific support. Right now all this conists of is
* to modify the ereport subclass to produce different ereport classes
@@ -39,11 +37,67 @@
#include <sys/cpu_module_ms_impl.h>
#include <sys/mc_intel.h>
#include <sys/pci_cfgspace.h>
+#include <sys/fm/protocol.h>
int gintel_ms_support_disable = 0;
int gintel_error_action_return = 0;
int gintel_ms_unconstrained = 0;
+int quickpath;
+int max_bus_number = 0xff;
+
+#define ERR_COUNTER_INDEX 2
+#define MAX_CPU_NODES 2
+#define N_MC_COR_ECC_CNT 6
+uint32_t err_counter_array[MAX_CPU_NODES][ERR_COUNTER_INDEX][N_MC_COR_ECC_CNT];
+uint8_t err_counter_index[MAX_CPU_NODES];
+
+#define MAX_BUS_NUMBER max_bus_number
+#define SOCKET_BUS(cpu) (MAX_BUS_NUMBER - (cpu))
+
+#define MC_COR_ECC_CNT(chipid, reg) (*pci_getl_func)(SOCKET_BUS(chipid), \
+ NEHALEM_EP_MEMORY_CONTROLLER_DEV, NEHALEM_EP_MEMORY_CONTROLLER_FUNC, \
+ 0x80 + (reg) * 4)
+
+#define MSCOD_MEM_ECC_READ 0x1
+#define MSCOD_MEM_ECC_SCRUB 0x2
+#define MSCOD_MEM_WR_PARITY 0x4
+#define MSCOD_MEM_REDUNDANT_MEM 0x8
+#define MSCOD_MEM_SPARE_MEM 0x10
+#define MSCOD_MEM_ILLEGAL_ADDR 0x20
+#define MSCOD_MEM_BAD_ID 0x40
+#define MSCOD_MEM_ADDR_PARITY 0x80
+#define MSCOD_MEM_BYTE_PARITY 0x100
+
+#define GINTEL_ERROR_MEM 0x1000
+#define GINTEL_ERROR_QUICKPATH 0x2000
+
+#define GINTEL_ERR_SPARE_MEM (GINTEL_ERROR_MEM | 1)
+#define GINTEL_ERR_MEM_UE (GINTEL_ERROR_MEM | 2)
+#define GINTEL_ERR_MEM_CE (GINTEL_ERROR_MEM | 3)
+#define GINTEL_ERR_MEM_PARITY (GINTEL_ERROR_MEM | 4)
+#define GINTEL_ERR_MEM_ADDR_PARITY (GINTEL_ERROR_MEM | 5)
+#define GINTEL_ERR_MEM_REDUNDANT (GINTEL_ERROR_MEM | 6)
+#define GINTEL_ERR_MEM_BAD_ADDR (GINTEL_ERROR_MEM | 7)
+#define GINTEL_ERR_MEM_BAD_ID (GINTEL_ERROR_MEM | 8)
+#define GINTEL_ERR_MEM_UNKNOWN (GINTEL_ERROR_MEM | 0xfff)
+
+#define MSR_MC_MISC_MEM_CHANNEL_MASK 0x00000000000c0000ULL
+#define MSR_MC_MISC_MEM_CHANNEL_SHIFT 18
+#define MSR_MC_MISC_MEM_DIMM_MASK 0x0000000000030000ULL
+#define MSR_MC_MISC_MEM_DIMM_SHIFT 16
+#define MSR_MC_MISC_MEM_SYNDROME_MASK 0xffffffff00000000ULL
+#define MSR_MC_MISC_MEM_SYNDROME_SHIFT 32
+
+#define CPU_GENERATION_DONT_CARE 0
+#define CPU_GENERATION_NEHALEM_EP 1
+
+#define INTEL_NEHALEM_CPU_FAMILY_ID 0x6
+#define INTEL_NEHALEM_CPU_MODEL_ID 0x1A
+
+#define NEHALEM_EP_MEMORY_CONTROLLER_DEV 0x3
+#define NEHALEM_EP_MEMORY_CONTROLLER_FUNC 0x2
+
/*ARGSUSED*/
int
gintel_init(cmi_hdl_t hdl, void **datap)
@@ -69,6 +123,11 @@ gintel_init(cmi_hdl_t hdl, void **datap)
if (!gintel_ms_unconstrained)
gintel_error_action_return |= CMS_ERRSCOPE_POISONED;
break;
+ case INTEL_QP_IO:
+ case INTEL_QP_36D:
+ case INTEL_QP_24D:
+ quickpath = 1;
+ break;
default:
break;
}
@@ -87,11 +146,266 @@ gintel_error_action(cmi_hdl_t hdl, int ismc, int bank,
}
/*ARGSUSED*/
+cms_cookie_t
+gintel_disp_match(cmi_hdl_t hdl, int bank, uint64_t status,
+ uint64_t addr, uint64_t misc, void *mslogout)
+{
+ cms_cookie_t rt = (cms_cookie_t)NULL;
+ uint16_t mcacode = MCAX86_ERRCODE(status);
+ uint16_t mscode = MCAX86_MSERRCODE(status);
+
+ if (MCAX86_ERRCODE_ISMEMORY_CONTROLLER(mcacode)) {
+ /*
+ * memory controller errors
+ */
+ if (mscode & MSCOD_MEM_SPARE_MEM) {
+ rt = (cms_cookie_t)GINTEL_ERR_SPARE_MEM;
+ } else if (mscode & (MSCOD_MEM_ECC_READ |
+ MSCOD_MEM_ECC_SCRUB)) {
+ if (status & MSR_MC_STATUS_UC)
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_UE;
+ else
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_CE;
+ } else if (mscode & (MSCOD_MEM_WR_PARITY |
+ MSCOD_MEM_BYTE_PARITY)) {
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_PARITY;
+ } else if (mscode & MSCOD_MEM_ADDR_PARITY) {
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_ADDR_PARITY;
+ } else if (mscode & MSCOD_MEM_REDUNDANT_MEM) {
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_REDUNDANT;
+ } else if (mscode & MSCOD_MEM_ILLEGAL_ADDR) {
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ADDR;
+ } else if (mscode & MSCOD_MEM_BAD_ID) {
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ID;
+ } else {
+ rt = (cms_cookie_t)GINTEL_ERR_MEM_UNKNOWN;
+ }
+ } else if (quickpath &&
+ MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status))) {
+ rt = (cms_cookie_t)GINTEL_ERROR_QUICKPATH;
+ }
+ return (rt);
+}
+
+/*ARGSUSED*/
void
gintel_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie,
const char **cpuclsp, const char **leafclsp)
{
*cpuclsp = FM_EREPORT_CPU_INTEL;
+ switch ((uintptr_t)mscookie) {
+ case GINTEL_ERROR_QUICKPATH:
+ *leafclsp = "quickpath.interconnect";
+ break;
+ case GINTEL_ERR_SPARE_MEM:
+ *leafclsp = "quickpath.mem_spare";
+ break;
+ case GINTEL_ERR_MEM_UE:
+ *leafclsp = "quickpath.mem_ue";
+ break;
+ case GINTEL_ERR_MEM_CE:
+ *leafclsp = "quickpath.mem_ce";
+ break;
+ case GINTEL_ERR_MEM_PARITY:
+ *leafclsp = "quickpath.mem_parity";
+ break;
+ case GINTEL_ERR_MEM_ADDR_PARITY:
+ *leafclsp = "quickpath.mem_addr_parity";
+ break;
+ case GINTEL_ERR_MEM_REDUNDANT:
+ *leafclsp = "quickpath.mem_redundant";
+ break;
+ case GINTEL_ERR_MEM_BAD_ADDR:
+ *leafclsp = "quickpath.mem_bad_addr";
+ break;
+ case GINTEL_ERR_MEM_BAD_ID:
+ *leafclsp = "quickpath.mem_bad_id";
+ break;
+ case GINTEL_ERR_MEM_UNKNOWN:
+ *leafclsp = "quickpath.mem_unknown";
+ break;
+ }
+}
+
+nvlist_t *
+gintel_ereport_detector(cmi_hdl_t hdl, cms_cookie_t mscookie, nv_alloc_t *nva)
+{
+ nvlist_t *nvl = (nvlist_t *)NULL;
+
+ if (mscookie) {
+ if ((nvl = fm_nvlist_create(nva)) == NULL)
+ return (NULL);
+ if ((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
+ "motherboard", 0,
+ "chip", cmi_hdl_chipid(hdl));
+ } else {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
+ "motherboard", 0,
+ "chip", cmi_hdl_chipid(hdl),
+ "memory-controller", 0);
+ }
+ }
+ return (nvl);
+}
+
+static nvlist_t *
+gintel_ereport_create_resource_elem(nv_alloc_t *nva, mc_unum_t *unump)
+{
+ nvlist_t *nvl, *snvl;
+
+ if ((nvl = fm_nvlist_create(nva)) == NULL) /* freed by caller */
+ return (NULL);
+
+ if ((snvl = fm_nvlist_create(nva)) == NULL) {
+ fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
+ return (NULL);
+ }
+
+ (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET,
+ unump->unum_offset);
+
+ if (unump->unum_chan == -1) {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 3,
+ "motherboard", unump->unum_board,
+ "chip", unump->unum_chip,
+ "memory-controller", unump->unum_mc);
+ } else if (unump->unum_cs == -1) {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 4,
+ "motherboard", unump->unum_board,
+ "chip", unump->unum_chip,
+ "memory-controller", unump->unum_mc,
+ "dram-channel", unump->unum_chan);
+ } else if (unump->unum_rank == -1) {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 5,
+ "motherboard", unump->unum_board,
+ "chip", unump->unum_chip,
+ "memory-controller", unump->unum_mc,
+ "dram-channel", unump->unum_chan,
+ "dimm", unump->unum_cs);
+ } else {
+ fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 6,
+ "motherboard", unump->unum_board,
+ "chip", unump->unum_chip,
+ "memory-controller", unump->unum_mc,
+ "dram-channel", unump->unum_chan,
+ "dimm", unump->unum_cs,
+ "rank", unump->unum_rank);
+ }
+
+ fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
+
+ return (nvl);
+}
+
+static void
+nehalem_ep_ereport_add_memory_error_counter(uint_t chipid,
+ uint32_t *this_err_counter_array)
+{
+ int index;
+
+ for (index = 0; index < N_MC_COR_ECC_CNT; index ++)
+ this_err_counter_array[index] = MC_COR_ECC_CNT(chipid, index);
+}
+
+static int
+gintel_cpu_generation()
+{
+ int cpu_generation = CPU_GENERATION_DONT_CARE;
+
+ if ((cpuid_getfamily(CPU) == INTEL_NEHALEM_CPU_FAMILY_ID) &&
+ (cpuid_getmodel(CPU) == INTEL_NEHALEM_CPU_MODEL_ID))
+ cpu_generation = CPU_GENERATION_NEHALEM_EP;
+
+ return (cpu_generation);
+}
+
+/*ARGSUSED*/
+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)
+{
+ mc_unum_t unum;
+ nvlist_t *resource;
+ uint32_t synd = 0;
+ int chan = MCAX86_ERRCODE_CCCC(status);
+ uint8_t last_index, this_index;
+ int chipid;
+
+ if (chan == 0xf)
+ chan = -1;
+
+ if ((uintptr_t)mscookie & GINTEL_ERROR_MEM) {
+ unum.unum_board = 0;
+ unum.unum_chip = cmi_hdl_chipid(hdl);
+ unum.unum_mc = 0;
+ unum.unum_chan = chan;
+ unum.unum_cs = -1;
+ unum.unum_rank = -1;
+ unum.unum_offset = -1ULL;
+ if (status & MSR_MC_STATUS_MISCV) {
+ unum.unum_chan =
+ (misc & MSR_MC_MISC_MEM_CHANNEL_MASK) >>
+ MSR_MC_MISC_MEM_CHANNEL_SHIFT;
+ unum.unum_cs =
+ (misc & MSR_MC_MISC_MEM_DIMM_MASK) >>
+ MSR_MC_MISC_MEM_DIMM_SHIFT;
+ synd = (misc & MSR_MC_MISC_MEM_SYNDROME_MASK) >>
+ MSR_MC_MISC_MEM_SYNDROME_SHIFT;
+ fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ECC_SYND,
+ DATA_TYPE_UINT32, synd, 0);
+ }
+ if (status & MSR_MC_STATUS_ADDRV) {
+ fm_payload_set(ereport, FM_FMRI_MEM_PHYSADDR,
+ DATA_TYPE_UINT64, addr, NULL);
+ (void) cmi_mc_patounum(addr, 0, 0, synd, 0, &unum);
+ }
+ resource = gintel_ereport_create_resource_elem(nva, &unum);
+ fm_payload_set(ereport, FM_EREPORT_PAYLOAD_NAME_RESOURCE,
+ DATA_TYPE_NVLIST_ARRAY, 1, &resource, NULL);
+ fm_nvlist_destroy(resource, nva ? FM_NVA_RETAIN:FM_NVA_FREE);
+
+ if (gintel_cpu_generation() == CPU_GENERATION_NEHALEM_EP) {
+
+ chipid = cmi_ntv_hwchipid(CPU);
+ if (chipid < MAX_CPU_NODES) {
+ last_index = err_counter_index[chipid];
+ this_index =
+ (last_index + 1) % ERR_COUNTER_INDEX;
+ err_counter_index[chipid] = this_index;
+ nehalem_ep_ereport_add_memory_error_counter(
+ chipid,
+ err_counter_array[chipid][this_index]);
+ fm_payload_set(ereport,
+ FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_THIS,
+ DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT,
+ err_counter_array[chipid][this_index],
+ NULL);
+ fm_payload_set(ereport,
+ FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_LAST,
+ DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT,
+ err_counter_array[chipid][last_index],
+ NULL);
+ }
+ }
+ }
+}
+
+boolean_t
+gintel_bankctl_skipinit(cmi_hdl_t hdl, int banknum)
+{
+ /*
+ * On Intel family 6 before QuickPath we must not enable machine check
+ * from bank 0 detectors. bank 0 is reserved for the platform
+ */
+
+ if (banknum == 0 &&
+ cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID &&
+ cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID)
+ return (1);
+ else
+ return (0);
}
cms_api_ver_t _cms_api_version = CMS_API_VERSION_0;
@@ -102,7 +416,7 @@ const cms_ops_t _cms_ops = {
NULL, /* cms_post_mpstartup */
NULL, /* cms_logout_size */
NULL, /* cms_mcgctl_val */
- NULL, /* cms_bankctl_skipinit */
+ gintel_bankctl_skipinit, /* cms_bankctl_skipinit */
NULL, /* cms_bankctl_val */
NULL, /* cms_bankstatus_skipinit */
NULL, /* cms_bankstatus_val */
@@ -110,11 +424,11 @@ const cms_ops_t _cms_ops = {
NULL, /* cms_poll_ownermask */
NULL, /* cms_bank_logout */
gintel_error_action, /* cms_error_action */
- NULL, /* cms_disp_match */
+ gintel_disp_match, /* cms_disp_match */
gintel_ereport_class, /* cms_ereport_class */
- NULL, /* cms_ereport_detector */
+ gintel_ereport_detector, /* cms_ereport_detector */
NULL, /* cms_ereport_includestack */
- NULL, /* cms_ereport_add_logout */
+ gintel_ereport_add_logout, /* cms_ereport_add_logout */
NULL, /* cms_msrinject */
NULL, /* cms_fini */
};
diff --git a/usr/src/uts/i86pc/intel_nhm/Makefile b/usr/src/uts/i86pc/intel_nhm/Makefile
new file mode 100644
index 0000000000..36e54ae808
--- /dev/null
+++ b/usr/src/uts/i86pc/intel_nhm/Makefile
@@ -0,0 +1,80 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = intel_nhm
+#
+INTEL_NHM_OBJS = nhm_init.o mem_addr.o intel_nhmdrv.o nhm_pci_cfg.o \
+ dimm_topo.o intel_nhm.o
+OBJECTS = $(INTEL_NHM_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(INTEL_NHM_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/i86pc/io/intel_nhm
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY) $(SRC_CONFFILE)
+LINT_TARGET = $(LINT_MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+CPPFLAGS += -I$(SRC)/uts/i86pc/cpu/genuineintel
+LDFLAGS += -dy -N drv/smbios
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include ../Makefile.targ
diff --git a/usr/src/uts/i86pc/io/intel_nhm/dimm_topo.c b/usr/src/uts/i86pc/io/intel_nhm/dimm_topo.c
new file mode 100644
index 0000000000..c9bd47fd28
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/dimm_topo.c
@@ -0,0 +1,278 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/nvpair.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/open.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/cyclic.h>
+#include <sys/errorq.h>
+#include <sys/stat.h>
+#include <sys/cpuvar.h>
+#include <sys/mc_intel.h>
+#include <sys/mc.h>
+#include <sys/fm/protocol.h>
+#include "nhm_log.h"
+#include "intel_nhm.h"
+
+extern nvlist_t *inhm_mc_nvl[MAX_CPU_NODES];
+extern char closed_page;
+extern char ecc_enabled;
+extern char lockstep[MAX_CPU_NODES];
+extern char mirror_mode[MAX_CPU_NODES];
+extern char spare_channel[MAX_CPU_NODES];
+
+static void
+inhm_vrank(nvlist_t *vrank, int num, uint64_t dimm_base, uint64_t limit,
+ uint32_t sinterleave, uint32_t cinterleave, uint32_t rinterleave,
+ uint32_t sway, uint32_t cway, uint32_t rway)
+{
+ char buf[128];
+
+ (void) snprintf(buf, sizeof (buf), "dimm-rank-base-%d", num);
+ (void) nvlist_add_uint64(vrank, buf, dimm_base);
+ (void) snprintf(buf, sizeof (buf), "dimm-rank-limit-%d", num);
+ (void) nvlist_add_uint64(vrank, buf, dimm_base + limit);
+ if (sinterleave > 1) {
+ (void) snprintf(buf, sizeof (buf), "dimm-socket-interleave-%d",
+ num);
+ (void) nvlist_add_uint32(vrank, buf, sinterleave);
+ (void) snprintf(buf, sizeof (buf),
+ "dimm-socket-interleave-way-%d", num);
+ (void) nvlist_add_uint32(vrank, buf, sway);
+ }
+ if (cinterleave > 1) {
+ (void) snprintf(buf, sizeof (buf), "dimm-channel-interleave-%d",
+ num);
+ (void) nvlist_add_uint32(vrank, buf, cinterleave);
+ (void) snprintf(buf, sizeof (buf),
+ "dimm-channel-interleave-way-%d", num);
+ (void) nvlist_add_uint32(vrank, buf, cway);
+ }
+ if (rinterleave > 1) {
+ (void) snprintf(buf, sizeof (buf), "dimm-rank-interleave-%d",
+ num);
+ (void) nvlist_add_uint32(vrank, buf, rinterleave);
+ (void) snprintf(buf, sizeof (buf),
+ "dimm-rank-interleave-way-%d", num);
+ (void) nvlist_add_uint32(vrank, buf, rway);
+ }
+}
+
+static void
+inhm_rank(nvlist_t *newdimm, nhm_dimm_t *nhm_dimm, uint32_t node,
+ uint8_t channel, uint32_t dimm, uint64_t rank_size)
+{
+ nvlist_t **newrank;
+ int num;
+ int i;
+ uint64_t dimm_base;
+ uint64_t vrank_sz;
+ uint64_t rank_addr;
+ uint64_t pa;
+ uint32_t sinterleave, cinterleave, rinterleave;
+ uint32_t sway, cway, rway;
+
+ newrank = kmem_zalloc(sizeof (nvlist_t *) * nhm_dimm->nranks, KM_SLEEP);
+ for (i = 0; i < nhm_dimm->nranks; i++) {
+ (void) nvlist_alloc(&newrank[i], NV_UNIQUE_NAME, KM_SLEEP);
+ rank_addr = 0;
+ num = 0;
+ while (rank_addr < rank_size) {
+ pa = dimm_to_addr(node, channel, dimm * 4 + i,
+ rank_addr, &dimm_base, &vrank_sz, &sinterleave,
+ &cinterleave, &rinterleave, &sway, &cway, &rway);
+ if (pa == -1)
+ break;
+ inhm_vrank(newrank[i], num, dimm_base,
+ vrank_sz * sinterleave * cinterleave * rinterleave,
+ sinterleave, cinterleave, rinterleave, sway, cway,
+ rway);
+ rank_addr += vrank_sz;
+ num++;
+ }
+
+ }
+ (void) nvlist_add_nvlist_array(newdimm, MCINTEL_NVLIST_RANKS, newrank,
+ nhm_dimm->nranks);
+ for (i = 0; i < nhm_dimm->nranks; i++)
+ nvlist_free(newrank[i]);
+ kmem_free(newrank, sizeof (nvlist_t *) * nhm_dimm->nranks);
+}
+
+static nvlist_t *
+inhm_dimm(nhm_dimm_t *nhm_dimm, uint32_t node, uint8_t channel, uint32_t dimm)
+{
+ nvlist_t *newdimm;
+ uint8_t t;
+ char sbuf[65];
+
+ (void) nvlist_alloc(&newdimm, NV_UNIQUE_NAME, KM_SLEEP);
+ (void) nvlist_add_uint32(newdimm, "dimm-number", dimm);
+
+ if (nhm_dimm->dimm_size >= 1024*1024*1024) {
+ (void) snprintf(sbuf, sizeof (sbuf), "%dG",
+ (int)(nhm_dimm->dimm_size / (1024*1024*1024)));
+ } else {
+ (void) snprintf(sbuf, sizeof (sbuf), "%dM",
+ (int)(nhm_dimm->dimm_size / (1024*1024)));
+ }
+ (void) nvlist_add_string(newdimm, "dimm-size", sbuf);
+ (void) nvlist_add_uint64(newdimm, "size", nhm_dimm->dimm_size);
+ (void) nvlist_add_uint32(newdimm, "nbanks", (uint32_t)nhm_dimm->nbanks);
+ (void) nvlist_add_uint32(newdimm, "ncolumn",
+ (uint32_t)nhm_dimm->ncolumn);
+ (void) nvlist_add_uint32(newdimm, "nrow", (uint32_t)nhm_dimm->nrow);
+ (void) nvlist_add_uint32(newdimm, "width", (uint32_t)nhm_dimm->width);
+ (void) nvlist_add_uint32(newdimm, "ranks", (uint32_t)nhm_dimm->nranks);
+ inhm_rank(newdimm, nhm_dimm, node, channel, dimm,
+ nhm_dimm->dimm_size / nhm_dimm->nranks);
+ if (nhm_dimm->manufacturer && nhm_dimm->manufacturer[0]) {
+ t = sizeof (nhm_dimm->manufacturer);
+ (void) strncpy(sbuf, nhm_dimm->manufacturer, t);
+ sbuf[t] = 0;
+ (void) nvlist_add_string(newdimm, "manufacturer", sbuf);
+ }
+ if (nhm_dimm->serial_number && nhm_dimm->serial_number[0]) {
+ t = sizeof (nhm_dimm->serial_number);
+ (void) strncpy(sbuf, nhm_dimm->serial_number, t);
+ sbuf[t] = 0;
+ (void) nvlist_add_string(newdimm, FM_FMRI_HC_SERIAL_ID, sbuf);
+ }
+ if (nhm_dimm->part_number && nhm_dimm->part_number[0]) {
+ t = sizeof (nhm_dimm->part_number);
+ (void) strncpy(sbuf, nhm_dimm->part_number, t);
+ sbuf[t] = 0;
+ (void) nvlist_add_string(newdimm, FM_FMRI_HC_PART, sbuf);
+ }
+ if (nhm_dimm->revision && nhm_dimm->revision[0]) {
+ t = sizeof (nhm_dimm->revision);
+ (void) strncpy(sbuf, nhm_dimm->revision, t);
+ sbuf[t] = 0;
+ (void) nvlist_add_string(newdimm, FM_FMRI_HC_REVISION, sbuf);
+ }
+ t = sizeof (nhm_dimm->label);
+ (void) strncpy(sbuf, nhm_dimm->label, t);
+ sbuf[t] = 0;
+ (void) nvlist_add_string(newdimm, FM_FAULT_FRU_LABEL, sbuf);
+ return (newdimm);
+}
+
+static void
+inhm_dimmlist(uint32_t node, nvlist_t *nvl)
+{
+ nvlist_t **dimmlist;
+ nvlist_t **newchannel;
+ int nchannels = CHANNELS_PER_MEMORY_CONTROLLER;
+ int nd;
+ uint8_t i, j;
+ nhm_dimm_t **dimmpp;
+ nhm_dimm_t *dimmp;
+
+ dimmlist = kmem_zalloc(sizeof (nvlist_t *) * MAX_DIMMS_PER_CHANNEL,
+ KM_SLEEP);
+ newchannel = kmem_zalloc(sizeof (nvlist_t *) * nchannels, KM_SLEEP);
+ dimmpp = &nhm_dimms[node * CHANNELS_PER_MEMORY_CONTROLLER *
+ MAX_DIMMS_PER_CHANNEL];
+ (void) nvlist_add_string(nvl, "memory-policy",
+ closed_page ? "closed-page" : "open-page");
+ (void) nvlist_add_string(nvl, "memory-ecc",
+ ecc_enabled ? lockstep[node] ? "x8" : "x4" : "no");
+ for (i = 0; i < nchannels; i++) {
+ (void) nvlist_alloc(&newchannel[i], NV_UNIQUE_NAME, KM_SLEEP);
+ (void) nvlist_add_string(newchannel[i], "channel-mode",
+ CHANNEL_DISABLED(MC_STATUS_RD(node), i) ? "disabled" :
+ i != 2 && lockstep[node] ? "lockstep" :
+ i != 2 && mirror_mode[node] ?
+ REDUNDANCY_LOSS(MC_RAS_STATUS_RD(node)) ?
+ "redundancy-loss" : "mirror" :
+ i == 2 && spare_channel[node] &&
+ !REDUNDANCY_LOSS(MC_RAS_STATUS_RD(node)) ? "spare" :
+ "independent");
+ nd = 0;
+ for (j = 0; j < MAX_DIMMS_PER_CHANNEL; j++) {
+ dimmp = *dimmpp;
+ if (dimmp != NULL) {
+ dimmlist[nd] = inhm_dimm(dimmp, node, i,
+ (uint32_t)j);
+ nd++;
+ }
+ dimmpp++;
+ }
+ if (nd) {
+ (void) nvlist_add_nvlist_array(newchannel[i],
+ "memory-dimms", dimmlist, nd);
+ for (j = 0; j < nd; j++)
+ nvlist_free(dimmlist[j]);
+ }
+ }
+ (void) nvlist_add_nvlist_array(nvl, MCINTEL_NVLIST_MC, newchannel,
+ nchannels);
+ for (i = 0; i < nchannels; i++)
+ nvlist_free(newchannel[i]);
+ kmem_free(dimmlist, sizeof (nvlist_t *) * MAX_DIMMS_PER_CHANNEL);
+ kmem_free(newchannel, sizeof (nvlist_t *) * nchannels);
+}
+
+char *
+inhm_mc_name()
+{
+ char *mc;
+
+ switch (nhm_chipset) {
+ case NHM_CPU:
+ mc = "Intel QuickPath";
+ break;
+ default:
+ mc = "Intel QuickPath";
+ break;
+ }
+ return (mc);
+}
+
+void
+inhm_create_nvl(int chip)
+{
+ nvlist_t *nvl;
+
+ (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
+ (void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_VERSTR,
+ MCINTEL_NVLIST_VERS);
+ (void) nvlist_add_string(nvl, MCINTEL_NVLIST_MEM, inhm_mc_name());
+ (void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_NMEM, 1);
+ (void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_NRANKS, 4);
+ inhm_dimmlist(chip, nvl);
+
+ if (inhm_mc_nvl[chip])
+ nvlist_free(inhm_mc_nvl[chip]);
+ inhm_mc_nvl[chip] = nvl;
+}
diff --git a/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.c b/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.c
new file mode 100644
index 0000000000..2cc190a7ac
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.c
@@ -0,0 +1,51 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/nvpair.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/open.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/cyclic.h>
+#include <sys/errorq.h>
+#include <sys/stat.h>
+#include <sys/cpuvar.h>
+#include <sys/mc_intel.h>
+#include <sys/mc.h>
+#include <sys/fm/protocol.h>
+#include "nhm_log.h"
+#include "intel_nhm.h"
+
+/*ARGSUSED*/
+void
+nhm_error_trap(cmi_hdl_t hdl, boolean_t ismc, boolean_t willpanic)
+{
+}
diff --git a/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.conf b/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.conf
new file mode 100644
index 0000000000..e56d524c97
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.conf
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+ddi-forceattach=1;
+demand-scrub=1;
+patrol-scrub=1;
diff --git a/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.h b/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.h
new file mode 100644
index 0000000000..9c11f3301a
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/intel_nhm.h
@@ -0,0 +1,221 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _INTEL_NHM_H
+#define _INTEL_NHM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NHM_CPU 0x2c408086
+
+#define MAX_CPU_NODES 2
+#define CPU_PCI_DEVS 6
+#define CPU_PCI_FUNCS 6
+
+#define MAX_BUS_NUMBER max_bus_number
+
+#define SOCKET_BUS(cpu) (MAX_BUS_NUMBER - (cpu))
+#define CPU_ID_RD(cpu) nhm_pci_getl(SOCKET_BUS(cpu), 0, 0, 0, 0)
+#define MC_CONTROL_RD(cpu) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 0, 0x48, 0)
+#define MC_STATUS_RD(cpu) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 0, 0x4c, 0)
+#define MC_SMI_SPARE_DIMM_ERROR_STATUS_RD(cpu) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 0, 0x50, 0)
+#define MC_SCRUB_CONTROL_RD(cpu) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, 0x4c, 0)
+#define MC_SCRUB_CONTROL_WR(cpu, reg) nhm_pci_putl(SOCKET_BUS(cpu), 3, 2, \
+ 0x4c, reg);
+#define MC_RAS_STATUS_RD(cpu) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, 0x54, 0)
+#define MC_SSR_CONTROL_RD(cpu) nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, 0x48, 0)
+#define MC_SSR_CONTROL_WR(cpu, reg) nhm_pci_putl(SOCKET_BUS(cpu), 3, 2, 0x48, \
+ reg);
+#define MC_SSR_SCRUB_CONTROL_RD(cpu) nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, \
+ 0x4c, 0)
+#define MC_RAS_ENABLES_RD(cpu) nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, 0x50, 0)
+#define MC_RAS_STATUS_RD(cpu) nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, 0x54, 0)
+#define MC_SSR_STATUS_RD(cpu) nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, 0x60, 0)
+#define MC_CHANNEL_MAPPER_RD(cpu) nhm_pci_getl(SOCKET_BUS(cpu), 3, 0, \
+ 0x60, 0)
+#define MC_COR_ECC_CNT_RD(cpu, select) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 2, 0x80 + ((select) * 4), 0)
+#define MC_CHANNEL_RANK_PRESENT_RD(cpu, channel) \
+ nhm_pci_getl(SOCKET_BUS(cpu), (channel) + 4, 0, 0x7c, 0)
+#define MC_DOD_RD(cpu, channel, select) \
+ nhm_pci_getl(SOCKET_BUS(cpu), (channel) + 4, 1, 0x48 + ((select) * 4), 0)
+#define MC_SAG_RD(cpu, channel, select) \
+ nhm_pci_getl(SOCKET_BUS(cpu), (channel) + 4, 1, 0x80 + ((select) * 4), 0)
+#define MC_RIR_LIMIT_RD(cpu, channel, select) \
+ nhm_pci_getl(SOCKET_BUS(cpu), (channel) + 4, 2, 0x40 + ((select) * 4), 0)
+#define MC_RIR_WAY_RD(cpu, channel, select) \
+ nhm_pci_getl(SOCKET_BUS(cpu), (channel) + 4, 2, 0x80 + ((select) * 4), 0)
+#define MC_CHANNEL_DIMM_INIT_PARAMS_RD(cpu, channel) \
+ nhm_pci_getl(SOCKET_BUS(cpu), (channel) + 4, 0, 0x58, 0)
+#define SAD_DRAM_RULE_RD(cpu, rule) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 0, 1, 0x80 + (4 * (rule)), 0)
+#define SAD_INTERLEAVE_LIST_RD(cpu, rule) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 0, 1, 0xc0 + (4 * (rule)), 0)
+#define TAD_DRAM_RULE_RD(cpu, rule) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 1, 0x80 + (4 * (rule)), 0)
+#define TAD_INTERLEAVE_LIST_RD(cpu, rule) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 1, 0xc0 + (4 * (rule)), 0)
+#define MC_DIMM_CLK_RATIO_STATUS(cpu) \
+ nhm_pci_getl(SOCKET_BUS(cpu), 3, 4, 0x50, 0)
+
+/*
+ * MC_CONTROL
+ */
+#define MC_CONTROL_CHANNEL_ACTIVE(reg, channel) \
+ ((reg) & (1 << (8 + (channel))) != 0)
+#define MC_CONTROL_ECCEN(reg) (((reg) >> 1) & 1)
+#define MC_CONTROL_CLOSED_PAGE(reg) ((reg) & 1)
+/*
+ * MC_STATUS
+ */
+#define CHANNEL_DISABLED(reg, channel) ((reg) & (1 << (channel)))
+/*
+ * MC_CHANNEL_DIMM_INIT_PARAMS
+ */
+#define THREE_DIMMS_PRESENT (1 << 24) /* not quad rank */
+#define SINGLE_QUAD_RANK_PRESENT (1 << 23)
+#define QUAD_RANK_PRESENT (1 << 22) /* 1 or 2 quad rank dimms */
+#define REGISTERED_DIMM (1 << 15)
+
+/*
+ * MC_DOD_CH
+ */
+#define RANKOFFSET(reg) (((reg) >> 10) & 7)
+#define DIMMPRESENT(reg) (((reg) & (1 << 9)) != 0)
+#define NUMBANK(reg) (((reg) & (3 << 7)) == 0 ? 4 : (((reg) >> 7) & 3) * 8)
+#define NUMRANK(reg) (((reg) & (3 << 5)) == 0 ? 1 : (((reg) >> 5) & 3) * 2)
+#define NUMROW(reg) ((((reg) >> 2) & 7) + 12)
+#define NUMCOL(reg) (((reg) & 3) + 10)
+#define DIMMWIDTH 8
+#define DIMMSIZE(reg) ((1ULL << (NUMCOL(reg) + NUMROW(reg))) * NUMRANK(reg) \
+ * NUMBANK(reg) * DIMMWIDTH)
+
+/*
+ * MC_SAG_CH
+ */
+#define DIVBY3(reg) (((reg) >> 27) & 1) /* 3 or 6 way interleave */
+#define REMOVE_6(reg) (((reg) >> 24) & 1)
+#define REMOVE_7(reg) (((reg) >> 25) & 1)
+#define REMOVE_8(reg) (((reg) >> 26) & 1)
+#define CH_ADDRESS_OFFSET(reg) \
+ ((int64_t)(((uint64_t)(reg) & 0x00ffffff) << 40) >> 40)
+/*
+ * MC_RIR_LIMIT_CH
+ */
+#define RIR_LIMIT(reg) ((((uint64_t)(reg) & 0x000003ff) + 1) << 28)
+/*
+ * MC_RIR_WAY_CH
+ */
+#define RIR_OFFSET(reg) ((int64_t)(((uint64_t)(reg) & 0x3ff0) << 50) >> 54)
+#define RIR_RANK(reg) ((reg) & 0xf)
+
+#define MAX_RIR_WAY 4
+
+/*
+ * MC_RAS_ENABLES
+ */
+#define RAS_LOCKSTEP_ENABLE(reg) (((reg) & 2) != 0)
+#define RAS_MIRROR_MEM_ENABLE(reg) (((reg) & 1) != 0)
+/*
+ * MC_RAS_STATUS
+ */
+#define REDUNDANCY_LOSS(reg) (((reg) & 1) != 0)
+/*
+ * MC_SSRSTATUS
+ */
+#define SPAREING_IN_PROGRESS(reg) (((reg) & 2) != 0)
+#define SPAREING_COMPLETE(reg) (((reg) & 1) != 0)
+
+/*
+ * MC_SSR_CONTROL
+ */
+#define SSR_MODE(reg) ((reg) & 3)
+#define SSR_IDLE 0
+#define SSR_SCRUB 1
+#define SSR_SPARE 2
+#define DEMAND_SCRUB_ENABLE (1 << 6)
+/*
+ * MC_SCRUB_CONTROL
+ */
+#define STARTSCRUB (1 << 24)
+/*
+ * MC_DIMM_CLK_RATIO_STATUS
+ */
+#define MAX_DIMM_CLK_RATIO(reg) (((reg) >> 24) & 0x1f)
+/*
+ * MC_SMI_SPARE_DIMM_ERROR_STATUS_RD
+ */
+#define REDUNDANCY_LOSS_FAILING_DIMM(status) (((status) >> 12) & 3)
+#define DIMM_ERROR_OVERFLOW_STATUS(status) ((status) & 0xfff)
+
+#define MAX_MEMORY_CONTROLLERS MAX_CPU_NODES
+#define CHANNELS_PER_MEMORY_CONTROLLER 3
+#define MAX_DIMMS_PER_CHANNEL 3
+
+/*
+ * SAD_DRAM_RULE
+ */
+#define SAD_DRAM_LIMIT(sad) ((((uint64_t)(sad) & 0x000fffc0ULL) + 0x40) << 20)
+#define SAD_DRAM_MODE(sad) (((sad) >> 1) & 3)
+#define SAD_DRAM_RULE_ENABLE(sad) ((sad) & 1)
+
+#define SAD_INTERLEAVE(list, num) (((list) >> ((num) * 4)) & 0x3)
+#define INTERLEAVE_NWAY 8
+#define MAX_SAD_DRAM_RULE 8
+
+/*
+ * TAD_DRAM_RULE
+ */
+#define TAD_DRAM_LIMIT(tad) ((((uint64_t)(tad) & 0x000fffc0ULL) + 0x40) << 20)
+#define TAD_DRAM_MODE(tad) (((tad) >> 1) & 3)
+#define TAD_DRAM_RULE_ENABLE(tad) ((tad) & 1)
+
+#define TAD_INTERLEAVE(list, channel) (((list) >> ((channel) * 4)) & 3)
+
+#define MAX_TAD_DRAM_RULE 8
+
+#define VRANK_SZ 0x40000000
+
+/*
+ * MC_CHANNEL_MAPPER
+ */
+#define CHANNEL_MAP(reg, channel, write) (((reg) >> ((channel) * 6 + \
+ ((write) ? 0 : 3))) & 7)
+
+extern int max_bus_number;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _INTEL_NHM_H */
diff --git a/usr/src/uts/i86pc/io/intel_nhm/intel_nhmdrv.c b/usr/src/uts/i86pc/io/intel_nhm/intel_nhmdrv.c
new file mode 100644
index 0000000000..a2c669b6a3
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/intel_nhmdrv.c
@@ -0,0 +1,347 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/nvpair.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/open.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/cyclic.h>
+#include <sys/errorq.h>
+#include <sys/stat.h>
+#include <sys/cpuvar.h>
+#include <sys/mc_intel.h>
+#include <sys/mc.h>
+#include <sys/fm/protocol.h>
+#include "nhm_log.h"
+#include "intel_nhm.h"
+
+int max_bus_number = 0xff;
+
+nvlist_t *inhm_mc_nvl[MAX_CPU_NODES];
+krwlock_t inhm_mc_lock;
+
+char *inhm_mc_snapshot[MAX_CPU_NODES];
+uint_t nhm_config_gen;
+uint_t inhm_mc_snapshotgen;
+size_t inhm_mc_snapshotsz[MAX_CPU_NODES];
+static dev_info_t *inhm_dip;
+int nhm_allow_detach = 0;
+
+extern int nhm_patrol_scrub;
+extern int nhm_demand_scrub;
+extern int nhm_no_smbios;
+extern int nhm_smbios_serial;
+extern int nhm_smbios_manufacturer;
+extern int nhm_smbios_part_number;
+extern int nhm_smbios_version;
+extern int nhm_smbios_label;
+
+extern void inhm_create_nvl(int);
+extern char *inhm_mc_name(void);
+extern void init_dimms(void);
+extern void nhm_smbios();
+
+static void
+inhm_mc_snapshot_destroy()
+{
+ int i;
+
+ ASSERT(RW_LOCK_HELD(&inhm_mc_lock));
+
+ for (i = 0; i < MAX_CPU_NODES; i++) {
+ if (inhm_mc_snapshot[i] == NULL)
+ continue;
+
+ kmem_free(inhm_mc_snapshot[i], inhm_mc_snapshotsz[i]);
+ inhm_mc_snapshot[i] = NULL;
+ inhm_mc_snapshotsz[i] = 0;
+ }
+ inhm_mc_snapshotgen++;
+}
+
+static int
+inhm_mc_snapshot_update()
+{
+ int i;
+ int rt = 0;
+
+ ASSERT(RW_LOCK_HELD(&inhm_mc_lock));
+
+ for (i = 0; i < MAX_CPU_NODES; i++) {
+ if (inhm_mc_snapshot[i] != NULL)
+ continue;
+
+ if (nvlist_pack(inhm_mc_nvl[i], &inhm_mc_snapshot[i],
+ &inhm_mc_snapshotsz[i], NV_ENCODE_XDR, KM_SLEEP) != 0)
+ rt = -1;
+ }
+
+ return (rt);
+}
+
+/*ARGSUSED*/
+static int
+inhm_mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rvalp)
+{
+ int rc = 0;
+ int chip;
+ mc_snapshot_info_t mcs;
+
+ if (cmd != MC_IOC_SNAPSHOT_INFO && cmd != MC_IOC_SNAPSHOT)
+ return (EINVAL);
+
+ rw_enter(&inhm_mc_lock, RW_READER);
+ chip = getminor(dev) % MAX_CPU_NODES;
+ if (inhm_mc_nvl[chip] == NULL ||
+ inhm_mc_snapshotgen != nhm_config_gen) {
+ if (!rw_tryupgrade(&inhm_mc_lock)) {
+ rw_exit(&inhm_mc_lock);
+ return (EAGAIN);
+ }
+ if (inhm_mc_nvl[chip])
+ inhm_mc_snapshot_destroy();
+ inhm_create_nvl(chip);
+ nhm_config_gen = inhm_mc_snapshotgen;
+ (void) inhm_mc_snapshot_update();
+ }
+ switch (cmd) {
+ case MC_IOC_SNAPSHOT_INFO:
+ mcs.mcs_size = (uint32_t)inhm_mc_snapshotsz[chip];
+ mcs.mcs_gen = inhm_mc_snapshotgen;
+
+ if (ddi_copyout(&mcs, (void *)arg, sizeof (mc_snapshot_info_t),
+ mode) < 0)
+ rc = EFAULT;
+ break;
+ case MC_IOC_SNAPSHOT:
+ if (ddi_copyout(inhm_mc_snapshot[chip], (void *)arg,
+ inhm_mc_snapshotsz[chip], mode) < 0)
+ rc = EFAULT;
+ break;
+ }
+ rw_exit(&inhm_mc_lock);
+ return (rc);
+}
+
+/*ARGSUSED*/
+static int
+inhm_mc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
+ void **result)
+{
+ if ((infocmd != DDI_INFO_DEVT2DEVINFO &&
+ infocmd != DDI_INFO_DEVT2INSTANCE) || inhm_dip == NULL) {
+ *result = NULL;
+ return (DDI_FAILURE);
+ }
+ if (infocmd == DDI_INFO_DEVT2DEVINFO)
+ *result = inhm_dip;
+ else
+ *result = (void *)(uintptr_t)ddi_get_instance(inhm_dip);
+ return (0);
+}
+
+static int
+inhm_mc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int i;
+ char buf[64];
+
+ if (cmd == DDI_RESUME) {
+ nhm_dev_reinit();
+ nhm_scrubber_enable();
+ nhm_smbios();
+ return (DDI_SUCCESS);
+ }
+ if (cmd != DDI_ATTACH)
+ return (DDI_FAILURE);
+ if (inhm_dip == NULL) {
+ inhm_dip = dip;
+ (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
+ inhm_mc_name());
+ nhm_pci_cfg_setup(dip);
+ if (nhm_dev_init()) {
+ nhm_pci_cfg_free();
+ inhm_dip = NULL;
+ return (DDI_FAILURE);
+ }
+ ddi_set_name_addr(dip, "1");
+ for (i = 0; i < MAX_CPU_NODES; i++) {
+ (void) snprintf(buf, sizeof (buf), "mc-intel-%d", i);
+ if (ddi_create_minor_node(dip, buf, S_IFCHR,
+ i, "ddi_mem_ctrl", 0) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "failed to create minor node"
+ " for memory controller %d\n", i);
+ }
+ }
+ cmi_hdl_walk(inhm_mc_register, NULL, NULL, NULL);
+ nhm_patrol_scrub = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "patrol-scrub", 0);
+ nhm_demand_scrub = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "demand-scrub", 0);
+ nhm_no_smbios = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "no-smbios", 0);
+ nhm_smbios_serial = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "smbios-dimm-serial", 1);
+ nhm_smbios_manufacturer = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "smbios-dimm-manufacturer", 1);
+ nhm_smbios_part_number = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "smbios-dimm-part-number", 1);
+ nhm_smbios_version = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "smbios-dimme-version", 1);
+ nhm_smbios_label = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "smbios-dimm-label", 1);
+ nhm_scrubber_enable();
+ nhm_smbios();
+ }
+
+ return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static int
+inhm_mc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ if (nhm_allow_detach && cmd == DDI_DETACH && dip == inhm_dip) {
+ rw_enter(&inhm_mc_lock, RW_WRITER);
+ inhm_mc_snapshot_destroy();
+ rw_exit(&inhm_mc_lock);
+ inhm_dip = NULL;
+ return (DDI_SUCCESS);
+ } else if (cmd == DDI_SUSPEND || cmd == DDI_PM_SUSPEND) {
+ return (DDI_SUCCESS);
+ } else {
+ return (DDI_FAILURE);
+ }
+}
+
+/*ARGSUSED*/
+static int
+inhm_mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ if (otyp != OTYP_CHR)
+ return (EINVAL);
+
+ rw_enter(&inhm_mc_lock, RW_READER);
+ if (getminor(*devp) >= MAX_CPU_NODES) {
+ rw_exit(&inhm_mc_lock);
+ return (EINVAL);
+ }
+ rw_exit(&inhm_mc_lock);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+inhm_mc_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ return (0);
+}
+
+
+static struct cb_ops inhm_mc_cb_ops = {
+ inhm_mc_open,
+ inhm_mc_close,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ nodev, /* no read routine */
+ nodev, /* no write routine */
+ inhm_mc_ioctl,
+ nodev, /* no devmap routine */
+ nodev, /* no mmap routine */
+ nodev, /* no segmap routine */
+ nochpoll, /* no chpoll routine */
+ ddi_prop_op,
+ 0, /* not a STREAMS driver */
+ D_NEW | D_MP, /* safe for multi-thread/multi-processor */
+};
+
+static struct dev_ops inhm_mc_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ inhm_mc_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ inhm_mc_attach, /* devo_attach */
+ inhm_mc_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &inhm_mc_cb_ops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ NULL /* devo_power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ "Intel QuickPath Memory Controller Hub Module",
+ &inhm_mc_ops
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modldrv,
+ NULL
+};
+
+int
+_init(void)
+{
+ int err;
+
+ err = nhm_init();
+ if (err == 0 && (err = mod_install(&modlinkage)) == 0) {
+ rw_init(&inhm_mc_lock, NULL, RW_DRIVER, NULL);
+ init_dimms();
+ }
+
+ return (err);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int err;
+
+ if ((err = mod_remove(&modlinkage)) == 0) {
+ nhm_unload();
+ rw_destroy(&inhm_mc_lock);
+ }
+
+ return (err);
+}
diff --git a/usr/src/uts/i86pc/io/intel_nhm/mem_addr.c b/usr/src/uts/i86pc/io/intel_nhm/mem_addr.c
new file mode 100644
index 0000000000..e61bf4dcc6
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/mem_addr.c
@@ -0,0 +1,913 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fm/protocol.h>
+#include <sys/cpu_module_impl.h>
+#include "intel_nhm.h"
+#include "nhm_log.h"
+
+struct sad {
+ uint64_t limit;
+ uint32_t node_list;
+ char mode;
+ char enable;
+ char interleave;
+} sad[MAX_SAD_DRAM_RULE];
+
+struct tad {
+ uint64_t limit;
+ uint32_t pkg_list;
+ char mode;
+ char enable;
+ char interleave;
+} tad[MAX_CPU_NODES][MAX_TAD_DRAM_RULE];
+
+struct sag_ch {
+ int32_t offset;
+ char divby3;
+ char remove6;
+ char remove7;
+ char remove8;
+} sag_ch[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER][MAX_TAD_DRAM_RULE];
+
+struct rir {
+ uint64_t limit;
+ struct rir_way {
+ int16_t offset;
+ uint8_t rank;
+ uint64_t rlimit;
+ } way[MAX_RIR_WAY];
+ char interleave;
+} rir[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER][MAX_TAD_DRAM_RULE];
+
+char closed_page;
+char ecc_enabled;
+char lockstep[2];
+char mirror_mode[2];
+char spare_channel[2];
+
+static int
+channel_in_interleave(int node, int channel, int rule, int *way_p,
+ int *no_interleave_p)
+{
+ int way;
+ int c;
+ int i;
+ uint32_t mc_channel_mapper;
+ int lc;
+ int rt = 0;
+ int start = 0;
+
+ if (lockstep[node] || mirror_mode[node]) {
+ *no_interleave_p = 0;
+ if (channel > 1)
+ return (0);
+ else
+ return (1);
+ }
+ mc_channel_mapper = MC_CHANNEL_MAPPER_RD(node);
+ lc = -1;
+ c = 1 << channel;
+ for (i = 0; i < CHANNELS_PER_MEMORY_CONTROLLER; i++) {
+ if ((CHANNEL_MAP(mc_channel_mapper, i, 0) & c) != 0) {
+ lc = i;
+ break;
+ }
+ }
+ if (lc == -1) {
+ for (i = 0; i < CHANNELS_PER_MEMORY_CONTROLLER; i++) {
+ if ((CHANNEL_MAP(mc_channel_mapper, i, 1) & c) != 0) {
+ lc = i;
+ break;
+ }
+ }
+ }
+ if (lc == -1) {
+ return (0);
+ }
+ *way_p = 0;
+ *no_interleave_p = 0;
+ if (node && tad[node][rule].mode == 2)
+ start = 4;
+ for (way = start; way < INTERLEAVE_NWAY; way++) {
+ if (lc == TAD_INTERLEAVE(tad[node][rule].pkg_list, way)) {
+ *way_p = way;
+ if (way == 0) {
+ for (i = way + 1; i < INTERLEAVE_NWAY; i++) {
+ c = TAD_INTERLEAVE(
+ tad[node][rule].pkg_list, i);
+ if (lc != c) {
+ break;
+ }
+ }
+ if (i == INTERLEAVE_NWAY)
+ *no_interleave_p = 1;
+ }
+ rt = 1;
+ break;
+ }
+ }
+ return (rt);
+}
+
+int
+address_to_node(uint64_t addr, int *interleave_p)
+{
+ int i;
+ int node = -1;
+ uint64_t base;
+ int way;
+ uchar_t package;
+
+ base = 0;
+ for (i = 0; i < MAX_SAD_DRAM_RULE; i++) {
+ if (sad[i].enable && addr >= base && addr < sad[i].limit) {
+ switch (sad[i].mode) {
+ case 0:
+ way = (addr >> 6) & 7;
+ break;
+ case 1:
+ way = ((addr >> 6) & 7) ^ ((addr >> 16) & 7);
+ break;
+ case 2:
+ way = ((addr >> 4) & 4) |
+ (((addr >> 6) & 0x3ffffffff) % 3);
+ break;
+ default:
+ return (-1);
+ }
+ package = SAD_INTERLEAVE(sad[i].node_list, way);
+ if (interleave_p)
+ *interleave_p = sad[i].interleave;
+ if (package == 1)
+ node = 0;
+ else if (package == 2)
+ node = 1;
+ else
+ node = -1;
+ break;
+ }
+ base = sad[i].limit;
+ }
+ return (node);
+}
+
+static uint64_t
+channel_address(int node, int channel, int rule, uint64_t addr)
+{
+ uint64_t caddr;
+
+ caddr = (((addr >> 16) +
+ (int64_t)sag_ch[node][channel][rule].offset) << 16) |
+ (addr & 0xffc0);
+ if (sag_ch[node][channel][rule].remove8) {
+ caddr = ((caddr >> 1) & ~0xff) | (caddr & 0xff);
+ }
+ if (sag_ch[node][channel][rule].remove7) {
+ caddr = ((caddr >> 1) & ~0x7f) | (caddr & 0x7f);
+ }
+ if (sag_ch[node][channel][rule].remove6) {
+ caddr = ((caddr >> 1) & ~0x3f) | (caddr & 0x3f);
+ }
+ caddr = caddr & 0x1fffffffff;
+ if (sag_ch[node][channel][rule].divby3) {
+ caddr = ((((caddr >> 6) / 3) << 6) & 0x1fffffffc0) |
+ (caddr & 0x3f);
+ }
+ return (caddr);
+}
+
+int
+address_to_channel(int node, uint64_t addr, int write, uint64_t *channel_addrp,
+ int *interleave_p)
+{
+ int i;
+ int channel = -1;
+ uint64_t base;
+ uint32_t mapper;
+ uint32_t lc;
+ int way;
+
+ base = 0;
+ for (i = 0; i < MAX_TAD_DRAM_RULE; i++) {
+ if (tad[node][i].enable && addr >= base &&
+ addr < tad[node][i].limit) {
+ switch (tad[node][i].mode) {
+ case 0:
+ way = (addr >> 6) & 7;
+ break;
+ case 1:
+ way = ((addr >> 6) & 7) ^ ((addr >> 16) & 7);
+ break;
+ case 2:
+ way = ((addr >> 4) & 4) |
+ (((addr >> 6) & 0x3ffffffff) % 3);
+ break;
+ default:
+ return (-1);
+ }
+ channel = TAD_INTERLEAVE(tad[node][i].pkg_list, way);
+ if (channel_addrp) {
+ *channel_addrp = channel_address(node, channel,
+ i, addr);
+ }
+ if (interleave_p)
+ *interleave_p = tad[node][i].interleave;
+ break;
+ }
+ base = tad[node][i].limit;
+ }
+ if (!lockstep[node] && channel != -1) {
+ mapper = MC_CHANNEL_MAPPER_RD(node);
+ lc = CHANNEL_MAP(mapper, channel, write);
+ switch (lc) {
+ case 1:
+ channel = 0;
+ break;
+ case 2:
+ channel = 1;
+ break;
+ case 4:
+ channel = 2;
+ break;
+ case 3: /* mirror PCH0 and PCH1 */
+ if (!write) {
+ if (((addr >> 24) & 1) ^ ((addr >> 12) & 1) ^
+ ((addr >> 6) & 1))
+ channel = 1;
+ else
+ channel = 0;
+ }
+ break;
+ case 5: /* sparing PCH0 to PCH2 */
+ channel = 0;
+ break;
+ case 6: /* sparing PCH1 to PCH2 */
+ channel = 1;
+ break;
+ }
+ }
+ return (channel);
+}
+
+int
+channels_interleave(uint64_t addr)
+{
+ int node;
+ int sinterleave;
+ int channels, channels1;
+
+ node = address_to_node(addr, &sinterleave);
+ if (sinterleave == 1) {
+ channels = 0;
+ (void) address_to_channel(node, addr, 0, 0, &channels);
+ } else {
+ channels = 0;
+ channels1 = 0;
+ (void) address_to_channel(0, addr, 0, 0, &channels);
+ (void) address_to_channel(1, addr, 0, 0, &channels1);
+ channels += channels1;
+ }
+ return (channels);
+}
+
+
+int
+caddr_to_dimm(int node, int channel, uint64_t caddr, int *rank_p,
+ uint64_t *rank_addr_p)
+{
+ int i;
+ uint64_t base;
+ uint64_t rank_addr;
+ int rank;
+ int dimm;
+ int way;
+
+ dimm = -1;
+ rank = -1;
+ base = 0;
+ rank_addr = -1ULL;
+ for (i = 0; i < MAX_TAD_DRAM_RULE; i++) {
+ if (caddr >= base && caddr < rir[node][channel][i].limit) {
+ if (closed_page) {
+ way = (caddr >> 6) & 3;
+ rank_addr = (((caddr + (int64_t)
+ rir[node][channel][i].way[way].offset *
+ VRANK_SZ) /
+ rir[node][channel][i].interleave) &
+ ~0x3f) + (caddr & 0x3f);
+ } else {
+ way = (caddr >> 12) & 3;
+ rank_addr = (((caddr + (int64_t)
+ rir[node][channel][i].way[way].offset *
+ VRANK_SZ) /
+ rir[node][channel][i].interleave) &
+ ~0xfff) + (caddr & 0xfff);
+ }
+ rank = rir[node][channel][i].way[way].rank;
+ dimm = rank >> 2;
+ break;
+ }
+ base = rir[node][channel][i].limit;
+ }
+ *rank_p = rank;
+ *rank_addr_p = rank_addr;
+ return (dimm);
+}
+
+static int
+socket_interleave(uint64_t addr, int node, int channel, int rule,
+ int *way_p)
+{
+ int i, j;
+ uint64_t base;
+ uchar_t package;
+ uchar_t xp;
+ uchar_t xc;
+ int ot = 0;
+ int mode;
+ int start;
+ int rt = 1;
+ int found = 0;
+
+ if (mirror_mode[node] || lockstep[node])
+ channel = 0;
+ package = node + 1;
+ mode = tad[node][rule].mode;
+ base = 0;
+ for (i = 0; i < MAX_SAD_DRAM_RULE; i++) {
+ if (sad[i].enable && addr >= base && addr < sad[i].limit) {
+ if (mode == 2) {
+ for (j = 0; j < INTERLEAVE_NWAY; j++) {
+ xp = SAD_INTERLEAVE(sad[i].node_list,
+ j);
+ if (package != xp) {
+ ot++;
+ if (found) {
+ rt = 2;
+ break;
+ }
+ } else {
+ found = 1;
+ if (ot) {
+ rt = 2;
+ break;
+ }
+ }
+ }
+ } else {
+ if (mode == 2)
+ start = *way_p;
+ else
+ start = 0;
+ for (j = start; j < INTERLEAVE_NWAY; j++) {
+ xp = SAD_INTERLEAVE(sad[i].node_list,
+ j);
+ if (package != xp) {
+ ot++;
+ if (found) {
+ rt = 2;
+ break;
+ }
+ } else if (!found) {
+ xc = TAD_INTERLEAVE(
+ tad[node][rule].pkg_list,
+ j);
+ if (channel == xc) {
+ *way_p = j;
+ if (ot) {
+ rt = 2;
+ break;
+ }
+ found = 1;
+ }
+ }
+ }
+ }
+ break;
+ }
+ base = sad[i].limit;
+ }
+ return (rt);
+}
+
+uint64_t
+dimm_to_addr(int node, int channel, int rank, uint64_t rank_addr,
+ uint64_t *rank_base_p, uint64_t *rank_sz_p, uint32_t *socket_interleave_p,
+ uint32_t *channel_interleave_p, uint32_t *rank_interleave_p,
+ uint32_t *socket_way_p, uint32_t *channel_way_p, uint32_t *rank_way_p)
+{
+ int i;
+ int way, xway;
+ uint64_t addr;
+ uint64_t caddr;
+ uint64_t cbaddr;
+ uint64_t baddr;
+ uint64_t rlimit;
+ uint64_t rank_sz;
+ uint64_t base;
+ int bits;
+ int no_interleave;
+ int sinterleave;
+ int cinterleave;
+ int rinterleave;
+ int found = 0;
+
+ addr = -1;
+ base = 0;
+ for (i = 0; i < MAX_TAD_DRAM_RULE && found == 0; i++) {
+ for (way = 0; way < MAX_RIR_WAY; way++) {
+ if (rir[node][channel][i].way[way].rank == rank) {
+ rlimit = rir[node][channel][i].way[way].rlimit;
+ if (rlimit && rank_addr >= rlimit)
+ continue;
+ if (closed_page) {
+ caddr = (rank_addr & ~0x3f) *
+ rir[node][channel][i].interleave -
+ (int64_t)rir[node][channel][i].
+ way[way].offset * VRANK_SZ;
+ cbaddr = caddr;
+ caddr += way << 6;
+ caddr |= rank_addr & 0x3f;
+ } else {
+ caddr = (rank_addr & ~0xfff) *
+ rir[node][channel][i].interleave -
+ (int64_t)rir[node][channel][i].
+ way[way].offset * VRANK_SZ;
+ cbaddr = caddr;
+ caddr += way << 12;
+ caddr |= rank_addr & 0xfff;
+ }
+ if (caddr < rir[node][channel][i].limit) {
+ rinterleave =
+ rir[node][channel][i].interleave;
+ rank_sz = (rir[node][channel][i].limit -
+ base) / rinterleave;
+ found = 1;
+ if (rank_interleave_p) {
+ *rank_interleave_p =
+ rinterleave;
+ }
+ if (rank_way_p)
+ *rank_way_p = way;
+ break;
+ }
+ }
+ }
+ base = rir[node][channel][i].limit;
+ }
+ if (!found)
+ return (-1ULL);
+ base = 0;
+ for (i = 0; i < MAX_TAD_DRAM_RULE; i++) {
+ way = 0;
+ if (tad[node][i].enable &&
+ channel_in_interleave(node, channel, i, &way,
+ &no_interleave)) {
+ bits = 0;
+ addr = caddr;
+ baddr = cbaddr;
+ if (sag_ch[node][channel][i].divby3) {
+ addr = (((addr >> 6) * 3) << 6) +
+ (addr & 0x3f);
+ baddr = (((baddr >> 6) * 3) << 6);
+ }
+ if (sag_ch[node][channel][i].remove6) {
+ bits = 1;
+ addr = ((addr & ~0x3f) << 1) | (addr & 0x3f);
+ baddr = (baddr & ~0x3f) << 1;
+ }
+ if (sag_ch[node][channel][i].remove7) {
+ bits = bits | 2;
+ addr = ((addr & ~0x7f) << 1) | (addr & 0x7f);
+ baddr = ((baddr & ~0x7f) << 1) | (baddr & 0x40);
+ }
+ if (sag_ch[node][channel][i].remove8) {
+ bits = bits | 4;
+ addr = ((addr & ~0xff) << 1) | (addr & 0xff);
+ baddr = ((baddr & ~0xff) << 1) | (baddr & 0xc0);
+ }
+ addr -= (int64_t)sag_ch[node][channel][i].offset << 16;
+ baddr -= (int64_t)
+ sag_ch[node][channel][i].offset << 16;
+ if (addr < tad[node][i].limit) {
+ sinterleave = socket_interleave(addr,
+ node, channel, i, &way);
+ if (socket_interleave_p) {
+ *socket_interleave_p = sinterleave;
+ }
+ if (socket_way_p)
+ *socket_way_p = way;
+ if ((no_interleave && sinterleave == 1) ||
+ mirror_mode[node] || lockstep[node]) {
+ cinterleave = 1;
+ } else {
+ cinterleave = channels_interleave(addr);
+ }
+ if (channel_interleave_p) {
+ *channel_interleave_p = cinterleave;
+ }
+ if (baddr + (rank_sz * rinterleave) >
+ tad[node][i].limit) {
+ rank_sz = (tad[node][i].limit - baddr) /
+ (cinterleave * sinterleave *
+ rinterleave);
+ }
+ if (rank_sz_p) {
+ *rank_sz_p = rank_sz;
+ }
+ if (rank_base_p)
+ *rank_base_p = baddr;
+ if (channel_way_p)
+ *channel_way_p = way;
+ if (sinterleave == 1 && no_interleave) {
+ break;
+ }
+ switch (tad[node][i].mode) {
+ case 0:
+ addr += way * 0x40;
+ break;
+ case 1:
+ way = (way ^ (addr >> 16)) & bits;
+ addr += way * 0x40;
+ break;
+ case 2:
+ if (sinterleave == 1) {
+ xway = ((addr >> 4) & 4) |
+ (((addr >> 6) &
+ 0x3ffffffff) % 3);
+ if (((way - xway) & 3) == 3)
+ xway = (way - xway) & 4;
+ else
+ xway = way - xway;
+ switch (xway) {
+ case 0:
+ way = 0;
+ break;
+ case 5:
+ way = 1;
+ break;
+ case 2:
+ way = 2;
+ break;
+ case 4:
+ way = 3;
+ break;
+ case 1:
+ way = 4;
+ break;
+ case 6:
+ way = 5;
+ break;
+ }
+ } else {
+ xway = (way & 3) -
+ (((addr >> 6) &
+ 0x3ffffffff) % 3);
+ if (xway < 0)
+ xway += 3;
+ switch (xway) {
+ case 0:
+ way = 0;
+ break;
+ case 1:
+ way = 1;
+ break;
+ case 2:
+ way = 2;
+ break;
+ }
+ }
+ addr += way * 0x40;
+ break;
+ }
+ break;
+ }
+ }
+ base = tad[node][i].limit;
+ }
+ return (addr);
+}
+
+/*ARGSUSED*/
+static cmi_errno_t
+nhm_patounum(void *arg, uint64_t pa, uint8_t valid_hi, uint8_t valid_lo,
+ uint32_t synd, int syndtype, mc_unum_t *unump)
+{
+ int node;
+ int channel;
+ int dimm;
+ int rank;
+ uint64_t caddr, raddr;
+
+ node = address_to_node(pa, 0);
+ if (node == -1)
+ return (CMIERR_UNKNOWN);
+ channel = address_to_channel(node, pa, syndtype, &caddr, 0);
+ if (channel == -1)
+ return (CMIERR_UNKNOWN);
+ dimm = caddr_to_dimm(node, channel, caddr, &rank, &raddr);
+ if (dimm == -1)
+ return (CMIERR_UNKNOWN);
+
+ unump->unum_board = 0;
+ unump->unum_chip = node;
+ unump->unum_mc = 0;
+ unump->unum_chan = channel;
+ unump->unum_cs = dimm;
+ unump->unum_rank = rank;
+ unump->unum_offset = raddr;
+
+ return (CMI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static cmi_errno_t
+nhm_unumtopa(void *arg, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap)
+{
+ uint64_t pa;
+ cmi_errno_t rt;
+ int node;
+ int channel;
+ int rank;
+ int i;
+ nvlist_t *fu, **hcl;
+ uint_t npr;
+ uint64_t rank_addr;
+ char *hcnm, *hcid;
+ long v;
+
+ if (unump == NULL) {
+ if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET,
+ &rank_addr) != 0 ||
+ nvlist_lookup_nvlist(nvl, FM_FMRI_MEM_UNUM "-fmri",
+ &fu) != 0 ||
+ nvlist_lookup_nvlist_array(fu, FM_FMRI_HC_LIST, &hcl,
+ &npr) != 0) {
+ if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR,
+ &pa) == 0) {
+ rt = CMI_SUCCESS;
+ *pap = pa;
+ return (rt);
+ }
+ return (CMIERR_UNKNOWN);
+ }
+ node = -1;
+ channel = -1;
+ rank = -1;
+ for (i = 0; i < npr; i++) {
+ if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME,
+ &hcnm) != 0 ||
+ nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID,
+ &hcid) != 0 ||
+ ddi_strtol(hcid, NULL, 0, &v) != 0)
+ return (CMIERR_UNKNOWN);
+ if (strcmp(hcnm, "chip") == 0)
+ node = (int)v;
+ else if (strcmp(hcnm, "dram-channel") == 0)
+ channel = (int)v;
+ else if (strcmp(hcnm, "rank") == 0)
+ rank = (int)v;
+ }
+ if (node == -1 || channel == -1 || rank == -1)
+ return (CMIERR_UNKNOWN);
+ } else {
+ node = unump->unum_chip;
+ channel = unump->unum_chan;
+ rank = unump->unum_rank;
+ rank_addr = unump->unum_offset;
+ }
+ pa = dimm_to_addr(node, channel, rank, rank_addr, 0, 0, 0, 0, 0, 0, 0,
+ 0);
+ if (pa == -1) {
+ rt = CMIERR_UNKNOWN;
+ } else {
+ rt = CMI_SUCCESS;
+ *pap = pa;
+ }
+ return (rt);
+}
+
+static const cmi_mc_ops_t nhm_mc_ops = {
+ nhm_patounum,
+ nhm_unumtopa,
+ nhm_error_trap /* cmi_mc_logout */
+};
+
+/*ARGSUSED*/
+int
+inhm_mc_register(cmi_hdl_t hdl, void *arg1, void *arg2, void *arg3)
+{
+ cmi_mc_register(hdl, &nhm_mc_ops, NULL);
+ return (CMI_HDL_WALK_NEXT);
+}
+
+static int
+choose_cpu(int *lastslot_p)
+{
+ uint32_t id;
+ int first;
+ int last;
+
+ first = 0;
+ last = MAX_CPU_NODES;
+ id = CPU_ID_RD(0);
+ if (id == NHM_CPU) {
+ id = CPU_ID_RD(1);
+ if (id != NHM_CPU) {
+ last = 1;
+ }
+ } else {
+ first = 1;
+ }
+ *lastslot_p = last;
+ return (first);
+}
+
+static int
+sad_interleave(uint32_t list)
+{
+ int rt = 1;
+ int i, j;
+ int p;
+
+ for (i = 1; i < INTERLEAVE_NWAY; i++) {
+ p = SAD_INTERLEAVE(list, i);
+ for (j = 0; j < i; j++) {
+ if (p == SAD_INTERLEAVE(list, j))
+ break;
+ }
+ if (i == j)
+ rt++;
+ }
+ return (rt);
+}
+
+static int
+tad_interleave(uint32_t list)
+{
+ int rt = 1;
+ int i, j;
+ int c;
+
+ for (i = 1; i < INTERLEAVE_NWAY; i++) {
+ c = TAD_INTERLEAVE(list, i);
+ for (j = 0; j < i; j++) {
+ if (c == TAD_INTERLEAVE(list, j))
+ break;
+ }
+ if (i == j)
+ rt++;
+ }
+ return (rt);
+}
+
+static void
+set_rank(int socket, int channel, int rule, int way, int rank,
+ uint64_t rank_addr)
+{
+ int k, l;
+ if (rank_addr == 0)
+ return;
+ for (k = 0; k <= rule; k++) {
+ for (l = 0; l < way; l++) {
+ if (rir[socket][channel][k].way[l].rank == rank &&
+ rir[socket][channel][k].way[l].rlimit == 0) {
+ rir[socket][channel][k].way[l].rlimit =
+ rank_addr;
+ }
+ }
+ }
+}
+
+void
+mem_reg_init()
+{
+ int i, j, k, l, m;
+ uint32_t sad_dram_rule;
+ uint32_t tad_dram_rule;
+ uint32_t mc_ras_enables;
+ uint32_t mc_channel_mapping;
+ uint32_t sagch;
+ uint32_t rir_limit;
+ uint32_t rir_way;
+ uint32_t mc_control;
+ int nhm_slot;
+ int nhm_lastslot;
+ uint8_t rank;
+ uint64_t base;
+
+ nhm_slot = choose_cpu(&nhm_lastslot);
+
+ for (i = 0; i < MAX_SAD_DRAM_RULE; i++) {
+ sad_dram_rule = SAD_DRAM_RULE_RD(nhm_slot, i);
+ sad[i].enable = SAD_DRAM_RULE_ENABLE(sad_dram_rule);
+ sad[i].limit = SAD_DRAM_LIMIT(sad_dram_rule);
+ sad[i].mode = SAD_DRAM_MODE(sad_dram_rule);
+ sad[i].node_list = SAD_INTERLEAVE_LIST_RD(nhm_slot, i);
+ sad[i].interleave = sad_interleave(sad[i].node_list);
+ }
+
+ for (i = nhm_slot; i < nhm_lastslot; i++) {
+ mc_ras_enables = MC_RAS_ENABLES_RD(i);
+ if (RAS_LOCKSTEP_ENABLE(mc_ras_enables))
+ lockstep[i] = 1;
+ if (RAS_MIRROR_MEM_ENABLE(mc_ras_enables))
+ mirror_mode[i] = 1;
+ mc_channel_mapping = MC_CHANNEL_MAPPER_RD(i);
+ if (CHANNEL_MAP(mc_channel_mapping, 2, 0) == 0 &&
+ CHANNEL_MAP(mc_channel_mapping, 2, 1) == 0)
+ spare_channel[i] = 1;
+ for (j = 0; j < MAX_TAD_DRAM_RULE; j++) {
+ tad_dram_rule = TAD_DRAM_RULE_RD(i, j);
+ tad[i][j].enable = TAD_DRAM_RULE_ENABLE(tad_dram_rule);
+ tad[i][j].limit = TAD_DRAM_LIMIT(tad_dram_rule);
+ tad[i][j].mode = TAD_DRAM_MODE(tad_dram_rule);
+ tad[i][j].pkg_list =
+ TAD_INTERLEAVE_LIST_RD(i, j);
+ if (mirror_mode[i] || lockstep[i]) {
+ tad[i][j].interleave = 1;
+ } else {
+ tad[i][j].interleave =
+ tad_interleave(tad[i][j].pkg_list);
+ if (spare_channel[i] &&
+ tad[i][j].interleave ==
+ CHANNELS_PER_MEMORY_CONTROLLER)
+ tad[i][j].interleave--;
+ }
+ }
+ for (j = 0; j < CHANNELS_PER_MEMORY_CONTROLLER; j++) {
+ m = 0;
+ base = 0;
+ for (k = 0; k < MAX_TAD_DRAM_RULE; k++) {
+ sagch = MC_SAG_RD(i, j, k);
+ sag_ch[i][j][k].offset =
+ CH_ADDRESS_OFFSET(sagch);
+ sag_ch[i][j][k].divby3 = DIVBY3(sagch);
+ sag_ch[i][j][k].remove6 = REMOVE_6(sagch);
+ sag_ch[i][j][k].remove7 = REMOVE_7(sagch);
+ sag_ch[i][j][k].remove8 = REMOVE_8(sagch);
+
+ rir_limit = MC_RIR_LIMIT_RD(i, j, k);
+ rir[i][j][k].limit = RIR_LIMIT(rir_limit);
+ for (l = 0; l < MAX_RIR_WAY; l++) {
+ rir_way = MC_RIR_WAY_RD(i, j, m);
+ rir[i][j][k].way[l].offset =
+ RIR_OFFSET(rir_way);
+ rir[i][j][k].way[l].rank =
+ RIR_RANK(rir_way);
+ rir[i][j][k].way[l].rlimit = 0;
+ m++;
+ }
+ rank = rir[i][j][k].way[0].rank;
+ if (rank == rir[i][j][k].way[1].rank &&
+ rank == rir[i][j][k].way[2].rank &&
+ rank == rir[i][j][k].way[3].rank) {
+ rir[i][j][k].interleave = 1;
+ } else if (rank == rir[i][j][k].way[1].rank ||
+ rank == rir[i][j][k].way[2].rank ||
+ rank == rir[i][j][k].way[3].rank) {
+ rir[i][j][k].interleave = 2;
+ } else {
+ rir[i][j][k].interleave = 4;
+ }
+ for (l = 0; l < MAX_RIR_WAY; l++) {
+ set_rank(i, j, k, l,
+ rir[i][j][k].way[l].rank,
+ ((rir[i][j][k].way[l].offset +
+ base) /
+ rir[i][j][k].interleave));
+ }
+ base = rir[i][j][k].limit;
+ }
+ }
+ }
+ mc_control = MC_CONTROL_RD(nhm_slot);
+ closed_page = MC_CONTROL_CLOSED_PAGE(mc_control);
+ ecc_enabled = MC_CONTROL_ECCEN(mc_control);
+}
diff --git a/usr/src/uts/i86pc/io/intel_nhm/nhm_init.c b/usr/src/uts/i86pc/io/intel_nhm/nhm_init.c
new file mode 100644
index 0000000000..9a55184429
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/nhm_init.c
@@ -0,0 +1,356 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/log.h>
+#include <sys/systm.h>
+#include <sys/modctl.h>
+#include <sys/errorq.h>
+#include <sys/controlregs.h>
+#include <sys/fm/util.h>
+#include <sys/fm/protocol.h>
+#include <sys/sysevent.h>
+#include <sys/pghw.h>
+#include <sys/cyclic.h>
+#include <sys/pci_cfgspace.h>
+#include <sys/mc_intel.h>
+#include <sys/cpu_module_impl.h>
+#include <sys/smbios.h>
+#include <sys/pci.h>
+#include <sys/machsystm.h>
+#include "intel_nhm.h"
+#include "nhm_log.h"
+
+errorq_t *nhm_queue;
+kmutex_t nhm_mutex;
+uint32_t nhm_chipset;
+
+nhm_dimm_t **nhm_dimms;
+
+uint64_t nhm_memory_on_ctl[MAX_MEMORY_CONTROLLERS];
+int nhm_patrol_scrub;
+int nhm_demand_scrub;
+int nhm_no_smbios;
+int nhm_smbios_serial;
+int nhm_smbios_manufacturer;
+int nhm_smbios_part_number;
+int nhm_smbios_version;
+int nhm_smbios_label;
+
+extern char ecc_enabled;
+extern void mem_reg_init(void);
+
+static void
+check_serial_number()
+{
+ nhm_dimm_t *dimmp, *tp;
+ nhm_dimm_t **dimmpp, **tpp;
+ nhm_dimm_t **end;
+ int not_unique;
+
+ end = &nhm_dimms[MAX_MEMORY_CONTROLLERS *
+ CHANNELS_PER_MEMORY_CONTROLLER * MAX_DIMMS_PER_CHANNEL];
+ for (dimmpp = nhm_dimms; dimmpp < end; dimmpp++) {
+ dimmp = *dimmpp;
+ if (dimmp == NULL)
+ continue;
+ not_unique = 0;
+ for (tpp = dimmpp + 1; tpp < end; tpp++) {
+ tp = *tpp;
+ if (tp == NULL)
+ continue;
+ if (strncmp(dimmp->serial_number, tp->serial_number,
+ sizeof (dimmp->serial_number)) == 0) {
+ not_unique = 1;
+ tp->serial_number[0] = 0;
+ }
+ }
+ if (not_unique)
+ dimmp->serial_number[0] = 0;
+ }
+}
+
+static void
+dimm_manufacture_data(smbios_hdl_t *shp, id_t id, nhm_dimm_t *dimmp)
+{
+ smbios_info_t cd;
+
+ if (smbios_info_common(shp, id, &cd) == 0) {
+ if (cd.smbi_serial && nhm_smbios_serial) {
+ (void) strncpy(dimmp->serial_number, cd.smbi_serial,
+ sizeof (dimmp->serial_number));
+ }
+ if (cd.smbi_manufacturer && nhm_smbios_manufacturer) {
+ (void) strncpy(dimmp->manufacturer,
+ cd.smbi_manufacturer,
+ sizeof (dimmp->manufacturer));
+ }
+ if (cd.smbi_part && nhm_smbios_part_number) {
+ (void) strncpy(dimmp->part_number, cd.smbi_part,
+ sizeof (dimmp->part_number));
+ }
+ if (cd.smbi_version && nhm_smbios_version) {
+ (void) strncpy(dimmp->revision, cd.smbi_version,
+ sizeof (dimmp->revision));
+ }
+ }
+}
+
+struct dimm_slot {
+ int controller;
+ int channel;
+ int dimm;
+ int max_dimm;
+};
+
+static int
+dimm_label(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
+{
+ nhm_dimm_t *dimmp;
+ smbios_memdevice_t md;
+ int slot;
+ int last_slot;
+ struct dimm_slot *dsp = (struct dimm_slot *)arg;
+
+ slot = (dsp->controller * CHANNELS_PER_MEMORY_CONTROLLER *
+ MAX_DIMMS_PER_CHANNEL) + (dsp->channel * MAX_DIMMS_PER_CHANNEL) +
+ dsp->dimm;
+ last_slot = MAX_MEMORY_CONTROLLERS * CHANNELS_PER_MEMORY_CONTROLLER *
+ MAX_DIMMS_PER_CHANNEL;
+ if (slot >= last_slot)
+ return (0);
+ dimmp = nhm_dimms[slot];
+ if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) {
+ if (smbios_info_memdevice(shp, sp->smbstr_id,
+ &md) == 0 && md.smbmd_dloc != NULL) {
+ if (dimmp == NULL && md.smbmd_size) {
+ /* skip non existent slot */
+ dsp->channel++;
+ if (dsp->dimm == 2)
+ dsp->max_dimm = 2;
+ dsp->dimm = 0;
+ slot = (dsp->controller *
+ CHANNELS_PER_MEMORY_CONTROLLER *
+ MAX_DIMMS_PER_CHANNEL) +
+ (dsp->channel * MAX_DIMMS_PER_CHANNEL);
+ if (slot >= last_slot)
+ return (0);
+
+ dimmp = nhm_dimms[slot];
+
+ if (dimmp == NULL) {
+ dsp->channel++;
+ if (dsp->channel ==
+ CHANNELS_PER_MEMORY_CONTROLLER) {
+ dsp->channel = 0;
+ dsp->controller++;
+ }
+ slot = (dsp->controller *
+ CHANNELS_PER_MEMORY_CONTROLLER *
+ MAX_DIMMS_PER_CHANNEL) +
+ (dsp->channel *
+ MAX_DIMMS_PER_CHANNEL);
+ if (slot >= last_slot)
+ return (0);
+ dimmp = nhm_dimms[slot];
+ }
+ }
+ if (dimmp) {
+ if (nhm_smbios_label)
+ (void) snprintf(dimmp->label,
+ sizeof (dimmp->label), "%s",
+ md.smbmd_dloc);
+ dimm_manufacture_data(shp, sp->smbstr_id,
+ dimmp);
+ }
+ }
+ dsp->dimm++;
+ if (dsp->dimm == dsp->max_dimm) {
+ dsp->dimm = 0;
+ dsp->channel++;
+ if (dsp->channel == CHANNELS_PER_MEMORY_CONTROLLER) {
+ dsp->channel = 0;
+ dsp->controller++;
+ }
+ }
+ }
+ return (0);
+}
+
+void
+nhm_smbios()
+{
+ struct dimm_slot ds;
+
+ if (ksmbios != NULL && nhm_no_smbios == 0) {
+ ds.dimm = 0;
+ ds.channel = 0;
+ ds.controller = 0;
+ ds.max_dimm = MAX_DIMMS_PER_CHANNEL;
+ (void) smbios_iter(ksmbios, dimm_label, &ds);
+ check_serial_number();
+ }
+}
+
+static void
+dimm_prop(nhm_dimm_t *dimmp, uint32_t dod)
+{
+ dimmp->dimm_size = DIMMSIZE(dod);
+ dimmp->nranks = NUMRANK(dod);
+ dimmp->nbanks = NUMBANK(dod);
+ dimmp->ncolumn = NUMCOL(dod);
+ dimmp->nrow = NUMROW(dod);
+ dimmp->width = DIMMWIDTH;
+}
+
+void
+nhm_scrubber_enable()
+{
+ uint32_t mc_ssrcontrol;
+ uint32_t mc_dimm_clk_ratio_status;
+ uint64_t cycle_time;
+ uint32_t interval;
+ int i;
+ int hw_scrub = 0;
+
+ if (ecc_enabled && (nhm_patrol_scrub || nhm_demand_scrub)) {
+ for (i = 0; i < MAX_MEMORY_CONTROLLERS; i++) {
+ if (nhm_memory_on_ctl[i] == 0)
+ continue;
+ mc_ssrcontrol = MC_SSR_CONTROL_RD(i);
+ if (nhm_demand_scrub &&
+ (mc_ssrcontrol & DEMAND_SCRUB_ENABLE) == 0) {
+ mc_ssrcontrol |= DEMAND_SCRUB_ENABLE;
+ MC_SSR_CONTROL_WR(i, mc_ssrcontrol);
+ }
+ if (nhm_patrol_scrub == 0)
+ continue;
+ if (SSR_MODE(mc_ssrcontrol) == SSR_IDLE) {
+ mc_dimm_clk_ratio_status =
+ MC_DIMM_CLK_RATIO_STATUS(i);
+ cycle_time =
+ MAX_DIMM_CLK_RATIO(mc_dimm_clk_ratio_status)
+ * 80000000;
+ interval = (uint32_t)((36400ULL * cycle_time) /
+ (nhm_memory_on_ctl[i]/64));
+ MC_SCRUB_CONTROL_WR(i, STARTSCRUB | interval);
+ MC_SSR_CONTROL_WR(i, mc_ssrcontrol | SSR_SCRUB);
+ } else if (SSR_MODE(mc_ssrcontrol) == SSR_SPARE) {
+ hw_scrub = 0;
+ break;
+ }
+ hw_scrub = 1;
+ }
+ if (hw_scrub)
+ memscrub_disable();
+ }
+}
+
+void
+init_dimms()
+{
+ int i, j, k;
+ nhm_dimm_t **dimmpp;
+ nhm_dimm_t *dimmp;
+ uint32_t dod;
+
+ nhm_dimms = (nhm_dimm_t **)kmem_zalloc(sizeof (nhm_dimm_t *) *
+ MAX_MEMORY_CONTROLLERS * CHANNELS_PER_MEMORY_CONTROLLER *
+ MAX_DIMMS_PER_CHANNEL, KM_SLEEP);
+ dimmpp = nhm_dimms;
+ for (i = 0; i < MAX_MEMORY_CONTROLLERS; i++) {
+ if (CPU_ID_RD(i) != NHM_CPU) {
+ dimmpp += CHANNELS_PER_MEMORY_CONTROLLER *
+ MAX_DIMMS_PER_CHANNEL;
+ continue;
+ }
+ for (j = 0; j < CHANNELS_PER_MEMORY_CONTROLLER; j++) {
+ for (k = 0; k < MAX_DIMMS_PER_CHANNEL; k++) {
+ dod = MC_DOD_RD(i, j, k);
+ if (DIMMPRESENT(dod)) {
+ dimmp = (nhm_dimm_t *)
+ kmem_zalloc(sizeof (nhm_dimm_t),
+ KM_SLEEP);
+ dimm_prop(dimmp, dod);
+ (void) snprintf(dimmp->label,
+ sizeof (dimmp->label),
+ "Socket %d channel %d dimm %d",
+ i, j, k);
+ *dimmpp = dimmp;
+ nhm_memory_on_ctl[i] +=
+ dimmp->dimm_size;
+ }
+ dimmpp++;
+ }
+ }
+ }
+}
+
+
+int
+nhm_init(void)
+{
+ int slot;
+
+ /* return ENOTSUP if there is no PCI config space support. */
+ if (pci_getl_func == NULL)
+ return (ENOTSUP);
+ for (slot = 0; slot < MAX_CPU_NODES; slot++) {
+ nhm_chipset = CPU_ID_RD(slot);
+ if (nhm_chipset == NHM_CPU)
+ break;
+ }
+ if (nhm_chipset != NHM_CPU) {
+ return (ENOTSUP);
+ }
+ mem_reg_init();
+ return (0);
+}
+
+int
+nhm_reinit(void)
+{
+ mem_reg_init();
+ return (0);
+}
+
+int
+nhm_dev_init()
+{
+ return (0);
+}
+
+void
+nhm_dev_reinit()
+{
+}
+
+void
+nhm_unload()
+{
+}
diff --git a/usr/src/uts/i86pc/io/intel_nhm/nhm_log.h b/usr/src/uts/i86pc/io/intel_nhm/nhm_log.h
new file mode 100644
index 0000000000..e3ba484d46
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/nhm_log.h
@@ -0,0 +1,85 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NHM_LOG_H
+#define _NHM_LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/cpu_module.h>
+
+typedef struct nhm_dimm {
+ uint64_t dimm_size;
+ uint8_t nranks;
+ uint8_t nbanks;
+ uint8_t ncolumn;
+ uint8_t nrow;
+ uint8_t width;
+ char manufacturer[64];
+ char serial_number[64];
+ char part_number[16];
+ char revision[2];
+ char label[64];
+} nhm_dimm_t;
+
+extern nhm_dimm_t **nhm_dimms;
+extern uint32_t nhm_chipset;
+
+extern errorq_t *nhm_queue;
+extern kmutex_t nhm_mutex;
+
+extern void nhm_drain(void *, const void *, const errorq_elem_t *);
+
+extern int nhm_init(void);
+extern int nhm_dev_init(void);
+extern void nhm_dev_reinit(void);
+extern void nhm_unload(void);
+extern void nhm_dev_unload(void);
+
+extern int inhm_mc_register(cmi_hdl_t, void *, void *, void *);
+extern void nhm_scrubber_enable(void);
+extern void nhm_error_trap(cmi_hdl_t, boolean_t, boolean_t);
+
+extern void nhm_pci_cfg_setup(dev_info_t *);
+extern void nhm_pci_cfg_free(void);
+
+extern uint8_t nhm_pci_getb(int, int, int, int, int *);
+extern uint16_t nhm_pci_getw(int, int, int, int, int *);
+extern uint32_t nhm_pci_getl(int, int, int, int, int *);
+extern void nhm_pci_putb(int, int, int, int, uint8_t);
+extern void nhm_pci_putw(int, int, int, int, uint16_t);
+extern void nhm_pci_putl(int, int, int, int, uint32_t);
+
+extern uint64_t dimm_to_addr(int, int, int, uint64_t, uint64_t *, uint64_t *,
+ uint32_t *, uint32_t *, uint32_t *, uint32_t *, uint32_t *, uint32_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NHM_LOG_H */
diff --git a/usr/src/uts/i86pc/io/intel_nhm/nhm_pci_cfg.c b/usr/src/uts/i86pc/io/intel_nhm/nhm_pci_cfg.c
new file mode 100644
index 0000000000..d7b8bed7d8
--- /dev/null
+++ b/usr/src/uts/i86pc/io/intel_nhm/nhm_pci_cfg.c
@@ -0,0 +1,159 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+#include <sys/sunddi.h>
+#include <sys/pci_cfgspace.h>
+#include <sys/pci.h>
+#include <sys/pcie.h>
+#include <vm/seg_kmem.h>
+#include <sys/machparam.h>
+#include <sys/mman.h>
+#include <sys/cpu_module.h>
+#include "intel_nhm.h"
+
+static ddi_acc_handle_t dev_pci_hdl[MAX_CPU_NODES][CPU_PCI_DEVS][CPU_PCI_FUNCS];
+
+void
+nhm_pci_cfg_setup(dev_info_t *dip)
+{
+ pci_regspec_t reg;
+ int i, j, k;
+
+ reg.pci_phys_mid = 0;
+ reg.pci_phys_low = 0;
+ reg.pci_size_hi = 0;
+ reg.pci_size_low = PCIE_CONF_HDR_SIZE; /* overriden in pciex */
+ for (i = 0; i < MAX_CPU_NODES; i++) {
+ for (j = 0; j < CPU_PCI_DEVS; j++) {
+ for (k = 0; k < CPU_PCI_FUNCS; k++) {
+ reg.pci_phys_hi = ((SOCKET_BUS(i))
+ << PCI_REG_BUS_SHIFT) +
+ (j << PCI_REG_DEV_SHIFT) +
+ (k << PCI_REG_FUNC_SHIFT);
+ if (ddi_prop_update_int_array(
+ DDI_MAJOR_T_UNKNOWN, dip, "reg",
+ (int *)&reg, sizeof (reg)/sizeof (int)) !=
+ DDI_PROP_SUCCESS)
+ cmn_err(CE_WARN, "nhm_pci_cfg_setup: "
+ "cannot create reg property");
+
+ if (pci_config_setup(dip,
+ &dev_pci_hdl[i][j][k]) != DDI_SUCCESS)
+ cmn_err(CE_WARN, "intel_nhm: "
+ "pci_config_setup failed");
+ }
+ }
+ }
+}
+
+void
+nhm_pci_cfg_free()
+{
+ int i, j, k;
+
+ for (i = 0; i < MAX_CPU_NODES; i++) {
+ for (j = 0; j < CPU_PCI_DEVS; j++) {
+ for (k = 0; k < CPU_PCI_FUNCS; k++) {
+ pci_config_teardown(&dev_pci_hdl[i][j][k]);
+ }
+ }
+ }
+}
+
+static ddi_acc_handle_t
+nhm_get_hdl(int bus, int dev, int func)
+{
+ ddi_acc_handle_t hdl;
+ int slot;
+
+ if (bus >= SOCKET_BUS(MAX_CPU_NODES) && bus <= SOCKET_BUS(0) &&
+ dev < CPU_PCI_DEVS && func < CPU_PCI_FUNCS) {
+ slot = SOCKET_BUS(0) - bus;
+ ASSERT(slot >= 0 && slot < MAX_CPU_NODES);
+ hdl = dev_pci_hdl[slot][dev][func];
+ } else {
+ hdl = 0;
+ }
+ return (hdl);
+}
+
+uint8_t
+nhm_pci_getb(int bus, int dev, int func, int reg, int *interpose)
+{
+ ddi_acc_handle_t hdl;
+
+ hdl = nhm_get_hdl(bus, dev, func);
+ return (cmi_pci_getb(bus, dev, func, reg, interpose, hdl));
+}
+
+uint16_t
+nhm_pci_getw(int bus, int dev, int func, int reg, int *interpose)
+{
+ ddi_acc_handle_t hdl;
+
+ hdl = nhm_get_hdl(bus, dev, func);
+ return (cmi_pci_getw(bus, dev, func, reg, interpose, hdl));
+}
+
+uint32_t
+nhm_pci_getl(int bus, int dev, int func, int reg, int *interpose)
+{
+ ddi_acc_handle_t hdl;
+
+ hdl = nhm_get_hdl(bus, dev, func);
+ return (cmi_pci_getl(bus, dev, func, reg, interpose, hdl));
+}
+
+void
+nhm_pci_putb(int bus, int dev, int func, int reg, uint8_t val)
+{
+ ddi_acc_handle_t hdl;
+
+ hdl = nhm_get_hdl(bus, dev, func);
+ cmi_pci_putb(bus, dev, func, reg, hdl, val);
+}
+
+void
+nhm_pci_putw(int bus, int dev, int func, int reg, uint16_t val)
+{
+ ddi_acc_handle_t hdl;
+
+ hdl = nhm_get_hdl(bus, dev, func);
+ cmi_pci_putw(bus, dev, func, reg, hdl, val);
+}
+
+void
+nhm_pci_putl(int bus, int dev, int func, int reg, uint32_t val)
+{
+ ddi_acc_handle_t hdl;
+
+ hdl = nhm_get_hdl(bus, dev, func);
+ cmi_pci_putl(bus, dev, func, reg, hdl, val);
+}
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.c b/usr/src/uts/i86pc/io/pcplusmp/apic.c
index 4bb54a3140..15f6673f09 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* PSMI 1.1 extensions are supported only in 2.6 and later versions.
* PSMI 1.2 extensions are supported only in 2.7 and later versions.
@@ -68,6 +66,7 @@
#include <sys/clock.h>
#include <sys/dditypes.h>
#include <sys/sunddi.h>
+#include <sys/x_call.h>
/*
* Local Function Prototypes
@@ -132,6 +131,14 @@ int apic_error_display_delay = 100;
int apic_cpcovf_vect;
int apic_enable_cpcovf_intr = 1;
+/* vector at which CMCI interrupts come in */
+int apic_cmci_vect;
+extern int cmi_enable_cmci;
+extern void cmi_cmci_trap(void);
+
+static kmutex_t cmci_cpu_setup_lock; /* protects cmci_cpu_setup_registered */
+static int cmci_cpu_setup_registered;
+
/*
* The following vector assignments influence the value of ipltopri and
* vectortoipl. Note that vectors 0 - 0x1f are not used. We can program
@@ -505,6 +512,48 @@ apic_cpcovf_mask_clear(void)
(apic_reg_ops->apic_read(APIC_PCINT_VECT) & ~APIC_LVT_MASK));
}
+/*ARGSUSED*/
+static int
+apic_cmci_enable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
+{
+ apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect);
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+apic_cmci_disable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
+{
+ apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect | AV_MASK);
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+cmci_cpu_setup(cpu_setup_t what, int cpuid, void *arg)
+{
+ cpuset_t cpu_set;
+
+ CPUSET_ONLY(cpu_set, cpuid);
+
+ switch (what) {
+ case CPU_ON:
+ xc_call(NULL, NULL, NULL, X_CALL_HIPRI, cpu_set,
+ (xc_func_t)apic_cmci_enable);
+ break;
+
+ case CPU_OFF:
+ xc_call(NULL, NULL, NULL, X_CALL_HIPRI, cpu_set,
+ (xc_func_t)apic_cmci_disable);
+ break;
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
static void
apic_init_intr()
{
@@ -635,6 +684,33 @@ apic_init_intr()
apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
}
+ /* Enable CMCI interrupt */
+ if (cmi_enable_cmci) {
+
+ mutex_enter(&cmci_cpu_setup_lock);
+ if (cmci_cpu_setup_registered == 0) {
+ mutex_enter(&cpu_lock);
+ register_cpu_setup_func(cmci_cpu_setup, NULL);
+ mutex_exit(&cpu_lock);
+ cmci_cpu_setup_registered = 1;
+ }
+ mutex_exit(&cmci_cpu_setup_lock);
+
+ if (apic_cmci_vect == 0) {
+ int ipl = 0x2;
+ int irq = apic_get_ipivect(ipl, -1);
+
+ ASSERT(irq != -1);
+ apic_cmci_vect = apic_irq_table[irq]->airq_vector;
+ ASSERT(apic_cmci_vect);
+
+ (void) add_avintr(NULL, ipl,
+ (avfunc)cmi_cmci_trap,
+ "apic cmci intr", irq, NULL, NULL, NULL, NULL);
+ }
+ apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect);
+ }
+
}
static void
diff --git a/usr/src/uts/i86pc/os/cmi.c b/usr/src/uts/i86pc/os/cmi.c
index ed96e3a205..031a764c3f 100644
--- a/usr/src/uts/i86pc/os/cmi.c
+++ b/usr/src/uts/i86pc/os/cmi.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Public interface to routines implemented by CPU modules
*/
@@ -71,6 +69,11 @@ int cmi_force_generic = 0;
int cmi_panic_on_uncorrectable_error = 1;
/*
+ * Set to indicate whether we are able to enable cmci interrupt.
+ */
+int cmi_enable_cmci = 0;
+
+/*
* Subdirectory (relative to the module search path) in which we will
* look for cpu modules.
*/
@@ -100,7 +103,8 @@ static kmutex_t cmi_load_lock;
* Functions we need from cmi_hw.c that are not part of the cpu_module.h
* interface.
*/
-extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t);
+extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t,
+ boolean_t);
extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *);
extern void *cmi_hdl_getcmi(cmi_hdl_t);
extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *);
@@ -431,7 +435,7 @@ cmi_load_generic(cmi_hdl_t hdl, void **datap)
cmi_hdl_t
cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
- uint_t strandid)
+ uint_t strandid, boolean_t mstrand)
{
cmi_t *cmi = NULL;
cmi_hdl_t hdl;
@@ -444,7 +448,8 @@ cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
mutex_enter(&cmi_load_lock);
- if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid)) == NULL) {
+ if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid,
+ mstrand)) == NULL) {
mutex_exit(&cmi_load_lock);
cmn_err(CE_WARN, "There will be no MCA support on chip %d "
"core %d strand %d (cmi_hdl_create returned NULL)\n",
@@ -755,6 +760,38 @@ cmi_hdl_poke(cmi_hdl_t hdl)
}
void
+cmi_cmci_trap()
+{
+#ifndef __xpv
+ cmi_hdl_t hdl = NULL;
+ cmi_t *cmi;
+
+ if (cmi_no_mca_init != 0)
+ return;
+
+ if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
+ cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
+ (cmi = HDL2CMI(hdl)) == NULL ||
+ !CMI_OP_PRESENT(cmi, cmi_cmci_trap)) {
+
+ cmn_err(CE_WARN, "CMCI interrupt on cpuid %d: %s",
+ CPU->cpu_id,
+ hdl ? "handle lookup ok but no CMCI handler found" :
+ "handle lookup failed");
+
+ if (hdl != NULL)
+ cmi_hdl_rele(hdl);
+
+ return;
+ }
+
+ CMI_OPS(cmi)->cmi_cmci_trap(hdl);
+
+ cmi_hdl_rele(hdl);
+#endif /* __xpv */
+}
+
+void
cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata)
{
if (!cmi_no_mca_init)
diff --git a/usr/src/uts/i86pc/os/cmi_hw.c b/usr/src/uts/i86pc/os/cmi_hw.c
index d728bacda0..66041d32e3 100644
--- a/usr/src/uts/i86pc/os/cmi_hw.c
+++ b/usr/src/uts/i86pc/os/cmi_hw.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* CPU Module Interface - hardware abstraction.
*/
@@ -43,6 +41,7 @@
#include <sys/ontrap.h>
#include <sys/controlregs.h>
#include <sys/sunddi.h>
+#include <sys/trap.h>
/*
* Outside of this file consumers use the opaque cmi_hdl_t. This
@@ -55,6 +54,7 @@ typedef struct cmi_hdl_impl {
uint_t cmih_chipid; /* Chipid of cpu resource */
uint_t cmih_coreid; /* Core within die */
uint_t cmih_strandid; /* Thread within core */
+ boolean_t cmih_mstrand; /* chip multithreading */
volatile uint32_t *cmih_refcntp; /* Reference count pointer */
uint64_t cmih_msrsrc; /* MSR data source flags */
void *cmih_hdlpriv; /* cmi_hw.c private data */
@@ -516,6 +516,12 @@ ntv_strandid(cmi_hdl_impl_t *hdl)
return (hdl->cmih_strandid);
}
+static boolean_t
+ntv_mstrand(cmi_hdl_impl_t *hdl)
+{
+ return (hdl->cmih_mstrand);
+}
+
static uint32_t
ntv_chiprev(cmi_hdl_impl_t *hdl)
{
@@ -651,22 +657,26 @@ ntv_wrmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
/*ARGSUSED*/
static int
-ntv_mcheck_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
+ntv_int_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
{
cmi_errno_t *rcp = (cmi_errno_t *)arg3;
+ int int_no = (int)arg1;
- int18();
+ if (int_no == T_MCE)
+ int18();
+ else
+ int_cmci();
*rcp = CMI_SUCCESS;
return (0);
}
static void
-ntv_mcheck(cmi_hdl_impl_t *hdl)
+ntv_int(cmi_hdl_impl_t *hdl, int int_no)
{
cpu_t *cp = (cpu_t *)hdl->cmih_hdlpriv;
- (void) call_func_ntv(cp->cpu_id, ntv_mcheck_xc, NULL, NULL);
+ (void) call_func_ntv(cp->cpu_id, ntv_int_xc, (xc_arg_t)int_no, NULL);
}
/*
@@ -681,6 +691,7 @@ struct cmi_hdl_ops {
uint_t (*cmio_chipid)(cmi_hdl_impl_t *);
uint_t (*cmio_coreid)(cmi_hdl_impl_t *);
uint_t (*cmio_strandid)(cmi_hdl_impl_t *);
+ boolean_t (*cmio_mstrand)(cmi_hdl_impl_t *);
uint32_t (*cmio_chiprev)(cmi_hdl_impl_t *);
const char *(*cmio_chiprevstr)(cmi_hdl_impl_t *);
uint32_t (*cmio_getsockettype)(cmi_hdl_impl_t *);
@@ -688,7 +699,7 @@ struct cmi_hdl_ops {
void (*cmio_setcr4)(cmi_hdl_impl_t *, ulong_t);
cmi_errno_t (*cmio_rdmsr)(cmi_hdl_impl_t *, uint_t, uint64_t *);
cmi_errno_t (*cmio_wrmsr)(cmi_hdl_impl_t *, uint_t, uint64_t);
- void (*cmio_mcheck)(cmi_hdl_impl_t *);
+ void (*cmio_int)(cmi_hdl_impl_t *, int);
} cmi_hdl_ops[] = {
/*
* CMI_HDL_NATIVE - ops when apparently running on bare-metal
@@ -702,6 +713,7 @@ struct cmi_hdl_ops {
ntv_chipid,
ntv_coreid,
ntv_strandid,
+ ntv_mstrand,
ntv_chiprev,
ntv_chiprevstr,
ntv_getsockettype,
@@ -709,7 +721,7 @@ struct cmi_hdl_ops {
ntv_setcr4,
ntv_rdmsr,
ntv_wrmsr,
- ntv_mcheck
+ ntv_int
},
};
@@ -746,7 +758,7 @@ cpu_search(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
cmi_hdl_t
cmi_hdl_create(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
- uint_t strandid)
+ uint_t strandid, boolean_t mstrand)
{
cmi_hdl_impl_t *hdl;
void *priv = NULL;
@@ -768,6 +780,7 @@ cmi_hdl_create(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
hdl->cmih_chipid = chipid;
hdl->cmih_coreid = coreid;
hdl->cmih_strandid = strandid;
+ hdl->cmih_mstrand = mstrand;
hdl->cmih_hdlpriv = priv;
hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_HWOK | CMI_MSR_FLAG_RD_INTERPOSEOK |
CMI_MSR_FLAG_WR_HWOK | CMI_MSR_FLAG_WR_INTERPOSEOK;
@@ -1012,14 +1025,15 @@ CMI_HDL_OPFUNC(stepping, uint_t)
CMI_HDL_OPFUNC(chipid, uint_t)
CMI_HDL_OPFUNC(coreid, uint_t)
CMI_HDL_OPFUNC(strandid, uint_t)
+CMI_HDL_OPFUNC(mstrand, boolean_t)
CMI_HDL_OPFUNC(chiprev, uint32_t)
CMI_HDL_OPFUNC(chiprevstr, const char *)
CMI_HDL_OPFUNC(getsockettype, uint32_t)
void
-cmi_hdl_mcheck(cmi_hdl_t ophdl)
+cmi_hdl_int(cmi_hdl_t ophdl, int num)
{
- IMPLHDL(ophdl)->cmih_ops->cmio_mcheck(IMPLHDL(ophdl));
+ IMPLHDL(ophdl)->cmih_ops->cmio_int(IMPLHDL(ophdl), num);
}
#ifndef __xpv
@@ -1054,6 +1068,15 @@ cmi_ntv_hwstrandid(cpu_t *cp)
return (cpuid_get_clogid(cp) % strands_per_core);
}
+
+boolean_t
+cmi_ntv_hwmstrand(cpu_t *cp)
+{
+ int strands_per_core = cpuid_get_ncpu_per_chip(cp) /
+ cpuid_get_ncore_per_chip(cp);
+
+ return (strands_per_core > 1);
+}
#endif /* __xpv */
void
diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c
index 55e1d85f6e..7bac886988 100644
--- a/usr/src/uts/i86pc/os/mp_startup.c
+++ b/usr/src/uts/i86pc/os/mp_startup.c
@@ -1599,7 +1599,8 @@ mp_startup(void)
cmi_hdl_t hdl;
if ((hdl = cmi_init(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
- cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) != NULL) {
+ cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU),
+ cmi_ntv_hwmstrand(CPU))) != NULL) {
if (x86_feature & X86_MCA)
cmi_mca_init(hdl);
}
diff --git a/usr/src/uts/i86pc/os/startup.c b/usr/src/uts/i86pc/os/startup.c
index b7f304ec77..fd3cb10732 100644
--- a/usr/src/uts/i86pc/os/startup.c
+++ b/usr/src/uts/i86pc/os/startup.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/t_lock.h>
#include <sys/param.h>
@@ -1486,7 +1484,8 @@ startup_modules(void)
cmi_hdl_t hdl;
if ((hdl = cmi_init(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
- cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) != NULL) {
+ cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU),
+ cmi_ntv_hwmstrand(CPU))) != NULL) {
if (x86_feature & X86_MCA)
cmi_mca_init(hdl);
}
diff --git a/usr/src/uts/i86pc/sys/apic.h b/usr/src/uts/i86pc/sys/apic.h
index 257f148914..e334225742 100644
--- a/usr/src/uts/i86pc/sys/apic.h
+++ b/usr/src/uts/i86pc/sys/apic.h
@@ -26,8 +26,6 @@
#ifndef _SYS_APIC_APIC_H
#define _SYS_APIC_APIC_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/psm_types.h>
#include <sys/avintr.h>
#include <sys/pci.h>
@@ -80,6 +78,7 @@ extern "C" {
#define APIC_LOCAL_TIMER 0xc8
/* Local Interrupt Vector registers */
+#define APIC_CMCI_VECT 0xbc
#define APIC_THERM_VECT 0xcc
#define APIC_PCINT_VECT 0xd0
#define APIC_INT_VECT0 0xd4
diff --git a/usr/src/uts/i86pc/sys/cpu_module.h b/usr/src/uts/i86pc/sys/cpu_module.h
index 9f5d7d2e85..1faac81cc7 100644
--- a/usr/src/uts/i86pc/sys/cpu_module.h
+++ b/usr/src/uts/i86pc/sys/cpu_module.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_CPU_MODULE_H
#define _SYS_CPU_MODULE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/cpuvar.h>
#include <sys/nvpair.h>
@@ -110,7 +108,8 @@ enum cmi_hdl_class {
struct regs;
struct cmi_mc_ops; /* defined in cpu_module_impl.h */
-extern cmi_hdl_t cmi_init(enum cmi_hdl_class, uint_t, uint_t, uint_t);
+extern cmi_hdl_t cmi_init(enum cmi_hdl_class, uint_t, uint_t, uint_t,
+ boolean_t);
extern void cmi_post_startup(void);
extern void cmi_post_mpstartup(void);
extern void cmi_fini(cmi_hdl_t);
@@ -147,6 +146,7 @@ extern uint_t cmi_hdl_chipid(cmi_hdl_t);
extern uint_t cmi_hdl_dieid(cmi_hdl_t);
extern uint_t cmi_hdl_coreid(cmi_hdl_t);
extern uint_t cmi_hdl_strandid(cmi_hdl_t);
+extern boolean_t cmi_hdl_mstrand(cmi_hdl_t);
extern uint32_t cmi_hdl_chiprev(cmi_hdl_t);
extern const char *cmi_hdl_chiprevstr(cmi_hdl_t);
extern uint32_t cmi_hdl_getsockettype(cmi_hdl_t);
@@ -155,6 +155,7 @@ extern uint32_t cmi_hdl_getsockettype(cmi_hdl_t);
extern uint_t cmi_ntv_hwchipid(cpu_t *);
extern uint_t cmi_ntv_hwcoreid(cpu_t *);
extern uint_t cmi_ntv_hwstrandid(cpu_t *);
+extern boolean_t cmi_ntv_hwmstrand(cpu_t *);
#endif /* __xpv */
typedef struct cmi_mca_regs {
@@ -184,7 +185,7 @@ extern void cmi_pci_putl(int, int, int, int, ddi_acc_handle_t, uint32_t);
extern void cmi_mca_init(cmi_hdl_t);
extern void cmi_hdl_poke(cmi_hdl_t);
-extern void cmi_hdl_mcheck(cmi_hdl_t);
+extern void cmi_hdl_int(cmi_hdl_t, int);
extern void cmi_mca_trap(struct regs *);
diff --git a/usr/src/uts/i86pc/sys/cpu_module_impl.h b/usr/src/uts/i86pc/sys/cpu_module_impl.h
index c072a2566b..4e64c06fa3 100644
--- a/usr/src/uts/i86pc/sys/cpu_module_impl.h
+++ b/usr/src/uts/i86pc/sys/cpu_module_impl.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_CPU_MODULE_IMPL_H
#define _SYS_CPU_MODULE_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/cpu_module.h>
#include <sys/cpuvar.h>
#include <sys/types.h>
@@ -48,8 +46,9 @@ typedef uint32_t cmi_api_ver_t;
#define CMI_API_VERSION_0 _CMI_API_VERSION(0)
#define CMI_API_VERSION_1 _CMI_API_VERSION(1)
+#define CMI_API_VERSION_2 _CMI_API_VERSION(2)
-#define CMI_API_VERSION CMI_API_VERSION_1
+#define CMI_API_VERSION CMI_API_VERSION_2
typedef struct cmi_mc_ops {
cmi_errno_t (*cmi_mc_patounum)(void *, uint64_t, uint8_t, uint8_t,
@@ -67,6 +66,7 @@ typedef struct cmi_ops {
void (*cmi_faulted_exit)(cmi_hdl_t);
void (*cmi_mca_init)(cmi_hdl_t);
uint64_t (*cmi_mca_trap)(cmi_hdl_t, struct regs *);
+ void (*cmi_cmci_trap)();
cmi_errno_t (*cmi_msrinject)(cmi_hdl_t, cmi_mca_regs_t *, uint_t, int);
void (*cmi_hdl_poke)(cmi_hdl_t);
void (*cmi_fini)(cmi_hdl_t);
diff --git a/usr/src/uts/intel/ia32/ml/i86_subr.s b/usr/src/uts/intel/ia32/ml/i86_subr.s
index 9f1a625a34..332fdb0628 100644
--- a/usr/src/uts/intel/ia32/ml/i86_subr.s
+++ b/usr/src/uts/intel/ia32/ml/i86_subr.s
@@ -30,8 +30,6 @@
* All Rights Reserved
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* General assembly language routines.
* It is the intent of this file to contain routines that are
@@ -1816,6 +1814,7 @@ repoutsd(int port, uint32_t *addr, int count)
* void int3(void)
* void int18(void)
* void int20(void)
+ * void int_cmci(void)
*/
#if defined(__lint)
@@ -1832,6 +1831,10 @@ void
int20(void)
{}
+void
+int_cmci(void)
+{}
+
#else /* __lint */
ENTRY(int3)
@@ -1855,6 +1858,11 @@ int20(void)
/* AMD Software Optimization Guide - Section 6.2 */
SET_SIZE(int20)
+ ENTRY(int_cmci)
+ int $T_ENOEXTFLT
+ ret
+ SET_SIZE(int_cmci)
+
#endif /* __lint */
#if defined(__lint)
diff --git a/usr/src/uts/intel/os/driver_aliases b/usr/src/uts/intel/os/driver_aliases
index c3a4cc328e..eb3ab9eff2 100644
--- a/usr/src/uts/intel/os/driver_aliases
+++ b/usr/src/uts/intel/os/driver_aliases
@@ -45,4 +45,5 @@ intel_nb5000 "pci8086,3600"
intel_nb5000 "pci8086,4000"
intel_nb5000 "pci8086,4001"
intel_nb5000 "pci8086,4003"
+intel_nhm "pci8086,3423"
xpv "pci5853,1.1"
diff --git a/usr/src/uts/intel/sys/archsystm.h b/usr/src/uts/intel/sys/archsystm.h
index 3caa017acd..9ce5b4031a 100644
--- a/usr/src/uts/intel/sys/archsystm.h
+++ b/usr/src/uts/intel/sys/archsystm.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_ARCHSYSTM_H
#define _SYS_ARCHSYSTM_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* A selection of ISA-dependent interfaces
*/
@@ -71,6 +69,7 @@ extern int interrupts_enabled(void);
extern void int3(void);
extern void int18(void);
extern void int20(void);
+extern void int_cmci(void);
#if defined(__amd64)
extern void sys_syscall();
diff --git a/usr/src/uts/intel/sys/fm/cpu/GMCA.h b/usr/src/uts/intel/sys/fm/cpu/GMCA.h
index c677efad87..0e5a5cf82d 100644
--- a/usr/src/uts/intel/sys/fm/cpu/GMCA.h
+++ b/usr/src/uts/intel/sys/fm/cpu/GMCA.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_FM_CPU_GMCA_H
#define _SYS_FM_CPU_GMCA_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -58,6 +56,7 @@ extern "C" {
#define FM_EREPORT_CPU_GENERIC_MC_CODE_PARITY "microcode_rom_parity"
#define FM_EREPORT_CPU_GENERIC_EXTERNAL "external"
#define FM_EREPORT_CPU_GENERIC_FRC "frc"
+#define FM_EREPORT_CPU_GENERIC_INTERNAL_PARITY "internal_parity"
#define FM_EREPORT_CPU_GENERIC_INTERNAL_TIMER "internal_timer"
#define FM_EREPORT_CPU_GENERIC_INTERNAL_UNCLASS "internal_unclassified"
@@ -77,6 +76,8 @@ extern "C" {
* 5 - II interpretation
* 6 - T interpretation
* 7 - "_uc" if this is a compound error with MCi_STATUS.UC set, else ""
+ * 8 - CCCC interpretation
+ * 9 - MMM interpretation
*
* They can be selected in the format string using the %n$s specifier form.
*
@@ -95,6 +96,7 @@ extern "C" {
#define FM_EREPORT_CPU_GENERIC_TLB "%2$s" "%1$s" "tlb" "%7$s"
#define FM_EREPORT_CPU_GENERIC_MEMHIER "%2$s" "%1$s" "cache" "%7$s"
#define FM_EREPORT_CPU_GENERIC_BUS_INTERCONNECT "bus_interconnect" "%5$s" "%7$s"
+#define FM_EREPORT_CPU_GENERIC_MEMORY_CONTROLLER "mc"
/*
* The "interpretation" expansions for the above ereport leaf subclasses.
@@ -130,6 +132,13 @@ extern "C" {
#define FM_EREPORT_CPU_GENERIC_T_NOTIMEOUT ""
#define FM_EREPORT_CPU_GENERIC_T_TIMEOUT ""
+#define FM_EREPORT_CPU_GENERIC_CCCC ""
+
+#define FM_EREPORT_CPU_GENERIC_MMM_ERR ""
+#define FM_EREPORT_CPU_GENERIC_MMM_RD ""
+#define FM_EREPORT_CPU_GENERIC_MMM_WR ""
+#define FM_EREPORT_CPU_GENERIC_MMM_ADRCMD ""
+
/*
* Ereport payload member names together with bitmask values to select
* their inclusion in ereports.
diff --git a/usr/src/uts/intel/sys/mc_intel.h b/usr/src/uts/intel/sys/mc_intel.h
index c7f17a03c1..1fae78927c 100644
--- a/usr/src/uts/intel/sys/mc_intel.h
+++ b/usr/src/uts/intel/sys/mc_intel.h
@@ -27,8 +27,6 @@
#ifndef _MC_INTEL_H
#define _MC_INTEL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -40,9 +38,12 @@ extern "C" {
#define MCINTEL_NVLIST_VERS MCINTEL_NVLIST_VERS0
+#define MCINTEL_NVLIST_MEM "memory-controller"
+#define MCINTEL_NVLIST_NMEM "memory-controllers"
#define MCINTEL_NVLIST_MC "memory-channels"
#define MCINTEL_NVLIST_DIMMS "memory-dimms"
#define MCINTEL_NVLIST_DIMMSZ "memory-dimm-size"
+#define MCINTEL_NVLIST_NRANKS "dimm-max-ranks"
#define MCINTEL_NVLIST_RANKS "dimm-ranks"
#define MCINTEL_NVLIST_ROWS "dimm-rows"
#define MCINTEL_NVLIST_COL "dimm-column"
@@ -190,6 +191,10 @@ extern "C" {
#define FM_EREPORT_PAYLOAD_INV_PIC "invalid-pic-request"
#define FM_EREPORT_PAYLOAD_CACHE_NERRORS "cache-error-count"
+#define FM_EREPORT_PAYLOAD_NAME_RESOURCE "resource"
+#define FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_THIS "mem_cor_ecc_counter"
+#define FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_LAST "mem_cor_ecc_counter_last"
+
#define INTEL_NB_5000P 0x25d88086
#define INTEL_NB_5000V 0x25d48086
#define INTEL_NB_5000X 0x25c08086
@@ -199,6 +204,57 @@ extern "C" {
#define INTEL_NB_5400B 0x40038086
#define INTEL_NB_7300 0x36008086
+#define INTEL_NHM 0x2c408086
+#define INTEL_QP_IO 0x34008086
+#define INTEL_QP_36D 0x34068086
+#define INTEL_QP_24D 0x34038086
+
+/* Intel QuickPath Bus Interconnect Errors */
+
+#define MSR_MC_STATUS_QP_HEADER_PARITY (1 << 16)
+#define MSR_MC_STATUS_QP_DATA_PARITY (1 << 17)
+#define MSR_MC_STATUS_QP_RETRIES_EXCEEDED (1 << 18)
+#define MSR_MC_STATUS_QP_POISON (1 << 19)
+
+#define MSR_MC_STATUS_QP_UNSUPPORTED_MSG (1 << 22)
+#define MSR_MC_STATUS_QP_UNSUPPORTED_CREDIT (1 << 23)
+#define MSR_MC_STATUS_QP_FLIT_BUF_OVER (1 << 24)
+#define MSR_MC_STATUS_QP_FAILED_RESPONSE (1 << 25)
+#define MSR_MC_STATUS_QP_CLOCK_JITTER (1 << 26)
+
+#define MSR_MC_MISC_QP_CLASS 0x000000ff
+#define MSR_MC_MISC_QP_RTID 0x00003f00
+#define MSR_MC_MISC_QP_RHNID 0x00070000
+#define MSR_MC_MISC_QP_IIB 0x01000000
+
+/* Intel QuickPath Memory Errors */
+
+#define MCAX86_COMPOUND_BUS_MEMORY 0x0080
+#define MCAX86_COMPOUND_BUS_MEMORY_MASK 0xff80
+#define MCAX86_COMPOUND_BUS_MEMORY_TRANSACTION 0x0070
+#define MCAX86_COMPOUND_BUS_MEMORY_READ 0x0010
+#define MCAX86_COMPOUND_BUS_MEMORY_WRITE 0x0020
+#define MCAX86_COMPOUND_BUS_MEMORY_CMD 0x0030
+#define MCAX86_COMPOUND_BUS_MEMORY_CHANNEL 0x000f
+
+#define MSR_MC_STATUS_MEM_ECC_READ (1 << 16)
+#define MSR_MC_STATUS_MEM_ECC_SCRUB (1 << 17)
+#define MSR_MC_STATUS_MEM_PARITY (1 << 18)
+#define MSR_MC_STATUS_MEM_REDUNDANT_MEM (1 << 19)
+#define MSR_MC_STATUS_MEM_SPARE_MEM (1 << 20)
+#define MSR_MC_STATUS_MEM_ILLEGAL_ADDR (1 << 21)
+#define MSR_MC_STATUS_MEM_BAD_ID (1 << 22)
+#define MSR_MC_STATUS_MEM_ADDR_PARITY (1 << 23)
+#define MSR_MC_STATUS_MEM_BYTE_PARITY (1 << 24)
+
+#define MSR_MC_MISC_MEM_RTID 0x00000000000000ffULL
+#define MSR_MC_MISC_MEM_DIMM 0x0000000000030000ULL
+#define MSR_MC_MISC_MEM_DIMM_SHIFT 16
+#define MSR_MC_MISC_MEM_CHANNEL 0x00000000000c0000ULL
+#define MSR_MC_MISC_MEM_CHANNEL_SHIFT 18
+#define MSR_MC_MISC_MEM_SYNDROME 0xffffffff00000000ULL
+#define MSR_MC_MISC_MEM_SYNDROME_SHIFT 32
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/intel/sys/mca_x86.h b/usr/src/uts/intel/sys/mca_x86.h
index 91b9a5bbfc..8e633f9a39 100644
--- a/usr/src/uts/intel/sys/mca_x86.h
+++ b/usr/src/uts/intel/sys/mca_x86.h
@@ -18,15 +18,13 @@
*
* CDDL HEADER END
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_MCA_X86_H
#define _SYS_MCA_X86_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Constants for the Memory Check Architecture as implemented on generic x86
* CPUs.
@@ -49,6 +47,7 @@ extern "C" {
#define MCG_CAP_CTL_P 0x00000100ULL
#define MCG_CAP_EXT_P 0x00000200ULL
#define MCG_CAP_TES_P 0x00000800ULL
+#define MCG_CAP_MISC2_P 0x00000400ULL
#define MCG_CAP_COUNT_MASK 0x000000ffULL
#define MCG_CAP_COUNT(cap) ((cap) & MCG_CAP_COUNT_MASK)
@@ -90,10 +89,13 @@ extern "C" {
#define _IA32_MSR_OFFSET_ADDR 0x2 /* offset within a bank */
#define _IA32_MSR_OFFSET_MISC 0x3 /* offset within a bank */
+#define _IA32_MSR_MC0_MISC2 0x280ULL /* first MCi_MISC2 reg */
#define IA32_MSR_MC(i, which) \
(_IA32_MSR_MC0_CTL + (i) * 4 + _IA32_MSR_OFFSET_##which)
+#define IA32_MSR_MC_MISC2(i) (_IA32_MSR_MC0_MISC2 + (i))
+
/*
* IA32_MSR_MCG_CAP.MCG_EXT_P indicates that a processor implements
* a set of extended machine-check registers starting at MSR 0x180;
@@ -189,10 +191,16 @@ typedef union mca_x86_mcistatus {
#define MSR_MC_STATUS_RESERVED_MASK 0x0180000000000000ULL
#define MSR_MC_STATUS_TBES_MASK 0x0060000000000000ULL
#define MSR_MC_STATUS_TBES_SHIFT 53
+#define MSR_MC_STATUS_CEC_MASK 0x001fffc000000000ULL
+#define MSR_MC_STATUS_CEC_SHIFT 38
#define MSR_MC_STATUS_MSERR_MASK 0x00000000ffff0000ULL
#define MSR_MC_STATUS_MSERR_SHIFT 16
#define MSR_MC_STATUS_MCAERR_MASK 0x000000000000ffffULL
+#define MSR_MC_MISC2_EN 0x0000000040000000ULL
+#define MSR_MC_MISC2_THRESHOLD_MASK 0x0000000000007fffULL
+#define MSR_MC_MISC2_THRESHOLD_OVERFLOW 0x0000000000004000ULL
+
/*
* Macros to extract error code and model-specific error code.
*/
@@ -265,6 +273,36 @@ typedef union mca_x86_mcistatus {
#define MCAX86_ERRCODE_T(code) \
(((code) & MCAX86_ERRCODE_T_MASK) >> MCAX86_ERRCODE_T_SHIFT)
+#define MCAX86_ERRCODE_MMM_MASK 0x0070
+#define MCAX86_ERRCODE_MMM_SHIFT 4
+#define MCAX86_ERRCODE_MMM_GEN 0x0
+#define MCAX86_ERRCODE_MMM_RD 0x1
+#define MCAX86_ERRCODE_MMM_WR 0x2
+#define MCAX86_ERRCODE_MMM_ADRCMD 0x3
+#define MCAX86_ERRCODE_MMM(code) \
+ (((code) & MCAX86_ERRCODE_MMM_MASK) >> MCAX86_ERRCODE_MMM_SHIFT)
+
+#define MCAX86_ERRCODE_CCCC_MASK 0x000f
+#define MCAX86_ERRCODE_CCCC_SHIFT 0
+#define MCAX86_ERRCODE_CCCC_CH0 0x0
+#define MCAX86_ERRCODE_CCCC_CH1 0x1
+#define MCAX86_ERRCODE_CCCC_CH2 0x2
+#define MCAX86_ERRCODE_CCCC_CH3 0x3
+#define MCAX86_ERRCODE_CCCC_CH4 0x4
+#define MCAX86_ERRCODE_CCCC_CH5 0x5
+#define MCAX86_ERRCODE_CCCC_CH6 0x6
+#define MCAX86_ERRCODE_CCCC_CH7 0x7
+#define MCAX86_ERRCODE_CCCC_CH8 0x8
+#define MCAX86_ERRCODE_CCCC_CH9 0x9
+#define MCAX86_ERRCODE_CCCC_CH10 0xa
+#define MCAX86_ERRCODE_CCCC_CH11 0xb
+#define MCAX86_ERRCODE_CCCC_CH12 0xc
+#define MCAX86_ERRCODE_CCCC_CH13 0xd
+#define MCAX86_ERRCODE_CCCC_CH14 0xe
+#define MCAX86_ERRCODE_CCCC_GEN 0xf
+#define MCAX86_ERRCODE_CCCC(code) \
+ (((code) & MCAX86_ERRCODE_CCCC_MASK) >> MCAX86_ERRCODE_CCCC_SHIFT)
+
/*
* Simple error encoding. MASKON are bits that must be set for a match
* at the same time bits indicated by MASKOFF are clear.
@@ -281,6 +319,9 @@ typedef union mca_x86_mcistatus {
#define MCAX86_SIMPLE_FRC_MASKON 0x0004
#define MCAX86_SIMPLE_FRC_MASKOFF 0xfffb
+#define MCAX86_SIMPLE_INTERNAL_PARITY_MASKON 0x0005
+#define MCAX86_SIMPLE_INTERNAL_PARITY_MASKOFF 0xfffa
+
#define MCAX86_SIMPLE_INTERNAL_TIMER_MASKON 0x0400
#define MCAX86_SIMPLE_INTERNAL_TIMER_MASKOFF 0xfbff
@@ -306,7 +347,7 @@ typedef union mca_x86_mcistatus {
*/
#define MCAX86_ERRCODE_ISSIMPLE(code) \
((code) >= MCAX86_SIMPLE_UNCLASSIFIED_MASKON && \
- (code) <= MCAX86_SIMPLE_FRC_MASKON || \
+ (code) <= MCAX86_SIMPLE_INTERNAL_PARITY_MASKON || \
(code) == MCAX86_SIMPLE_INTERNAL_TIMER_MASKON || \
MCAX86_ERRCODE_ISSIMPLE_INTERNAL_UNCLASS(code))
@@ -326,6 +367,9 @@ typedef union mca_x86_mcistatus {
#define MCAX86_COMPOUND_BUS_INTERCONNECT_MASKON 0x0800
#define MCAX86_COMPOUND_BUS_INTERCONNECT_MASKOFF 0xe000
+#define MCAX86_COMPOUND_MEMORY_CONTROLLER_MASKON 0x0080
+#define MCAX86_COMPOUND_MEMORY_CONTROLLER_MASKOFF 0xff00
+
/*
* Macros to make compound error codes and to test for each type.
*/
@@ -368,11 +412,21 @@ typedef union mca_x86_mcistatus {
MCAX86_COMPOUND_BUS_INTERCONNECT_MASKON && \
((code) & MCAX86_COMPOUND_BUS_INTERCONNECT_MASKOFF) == 0)
+#define MCAX86_MKERRCODE_MEMORY_CONTROLLER (mmm, cccc) \
+ (MCAX86_COMPOUNT_MEMORY_CONTROLLER_MASKON | \
+ ((mmm) << MCAX86_ERRCODE_MMM_SHIFT & MCAX86_ERRCODE_MMM_MASK) | \
+ ((cccc) << MCAX86_ERRCODE_CCCC_SHIFT & MCAX86_ERRCODE_CCCC_MASK))
+#define MCAX86_ERRCODE_ISMEMORY_CONTROLLER(code) \
+ (((code) & MCAX86_COMPOUND_MEMORY_CONTROLLER_MASKON) == \
+ MCAX86_COMPOUND_MEMORY_CONTROLLER_MASKON && \
+ ((code) & MCAX86_COMPOUND_MEMORY_CONTROLLER_MASKOFF) == 0)
+
#define MCAX86_ERRCODE_ISCOMPOUND(code) \
(MCAX86_ERRCODE_ISGENERIC_MEMHIER(code) || \
MCAX86_ERRCODE_ISTLB(code) || \
- MCAX86_ERRCODE_ISMEMHIER(code) \
- MCAX86_ERRCODE_ISBUS_INTERCONNECT(code))
+ MCAX86_ERRCODE_ISMEMHIER(code) || \
+ MCAX86_ERRCODE_ISBUS_INTERCONNECT(code) || \
+ MCAX86_ERRCODE_ISMEMORY_CONTROLLER(code))
#define MCAX86_ERRCODE_UNKNOWN(code) \
(!MCAX86_ERRCODE_ISSIMPLE(code) && !MCAX86_ERRCODE_ISCOMPOUND(code))